Ricerca…


Func e azione

Func fornisce un supporto per le funzioni anonime parametrizzate. I tipi principali sono gli input e l'ultimo tipo è sempre il valore restituito.

// square a number.
Func<double, double> square = (x) => { return x * x; };

// get the square root.
// note how the signature matches the built in method.
Func<double, double> squareroot = Math.Sqrt;

// provide your workings.
Func<double, double, string> workings = (x, y) => 
    string.Format("The square of {0} is {1}.", x, square(y))

Gli oggetti azione sono come metodi void quindi hanno solo un tipo di input. Nessun risultato è inserito nello stack di valutazione.

// right-angled triangle.
class Triangle
{
    public double a;
    public double b;
    public double h;
}

// Pythagorean theorem.
Action<Triangle> pythagoras = (x) => 
    x.h = squareroot(square(x.a) + square(x.b));

Triangle t = new Triangle { a = 3, b = 4 };
pythagoras(t);
Console.WriteLine(t.h); // 5.

Immutabilità

L'immutabilità è comune nella programmazione funzionale e rara nella programmazione orientata agli oggetti.

Creare, ad esempio, un tipo di indirizzo con stato mutabile:

public class Address () 
{
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string City  { get; set; }
}

Qualsiasi parte di codice potrebbe alterare qualsiasi proprietà nell'oggetto sopra.

Ora crea il tipo di indirizzo immutabile:

public class Address () 
{
    public readonly string Line1;
    public readonly string Line2;
    public readonly string City;

    public Address(string line1, string line2, string city) 
    {
        Line1 = line1;
        Line2 = line2;
        City  = city;
    }
}

Ricordare che disporre di raccolte di sola lettura non rispetta l'immutabilità. Per esempio,

public class Classroom
{
    public readonly List<Student> Students;
    
    public Classroom(List<Student> students)
    {
        Students = students;
    }
}

non è immutabile, in quanto l'utente dell'oggetto può modificare la raccolta (aggiungere o rimuovere elementi da essa). Per renderlo immutabile, si deve usare un'interfaccia come IEnumerable, che non espone i metodi da aggiungere, o per renderlo un ReadOnlyCollection.

public class Classroom
{
    public readonly ReadOnlyCollection<Student> Students;

    public Classroom(ReadOnlyCollection<Student> students)
    {
        Students = students;
    }
}

List<Students> list = new List<Student>();
// add students
Classroom c = new Classroom(list.AsReadOnly());   

Con l'oggetto immutabile abbiamo i seguenti vantaggi:

  • Sarà in uno stato noto (altro codice non può cambiarlo).
  • È thread-safe.
  • Il costruttore offre un singolo posto per la convalida.
  • Sapere che l'oggetto non può essere modificato rende il codice più facile da capire.

Evita riferimenti null

Gli sviluppatori C # ottengono un sacco di eccezioni di riferimento null da gestire. Gli sviluppatori di F # non lo fanno perché hanno il tipo Option. Un tipo di opzione <> (alcuni preferiscono forse <> come nome) fornisce un tipo di ritorno Some e None. Rende esplicito che un metodo potrebbe essere in procinto di restituire un record nullo.

Ad esempio, non puoi leggere quanto segue e sapere se dovrai gestire un valore nullo.

var user = _repository.GetUser(id);

Se si conosce l'eventuale null, è possibile introdurre un codice di codice per affrontarlo.

var username = user != null ? user.Name : string.Empty;

Cosa succede se invece è stata restituita un'opzione <>?

Option<User> maybeUser = _repository.GetUser(id);

Il codice ora rende esplicito che potremmo avere un record None restituito e il codice boilerplate da verificare per Some o None è richiesto:

var username = maybeUser.HasValue ? maybeUser.Value.Name : string.Empty;

Il seguente metodo mostra come restituire un'opzione <>

public Option<User> GetUser(int id)
{
    var users = new List<User>
    {
        new User { Id = 1, Name = "Joe Bloggs" },
        new User { Id = 2, Name = "John Smith" }
    };

    var user = users.FirstOrDefault(user => user.Id == id);

    return user != null ? new Option<User>(user) : new Option<User>();
}

Ecco un'implementazione minima dell'opzione <>.

public struct Option<T>
{
    private readonly T _value;

    public T Value
    {
        get
        {
            if (!HasValue)
                throw new InvalidOperationException();

            return _value;
        }
    }

    public bool HasValue
    {
        get { return _value != null; }
    }

    public Option(T value)
    {
        _value = value;
    }

    public static implicit operator Option<T>(T value)
    {
        return new Option<T>(value);
    }
}

Per dimostrare quanto sopra avoidNull.csx può essere eseguito con C # REPL.

Come affermato, questa è un'implementazione minima. Una ricerca di pacchetti "Forse" NuGet mostrerà un buon numero di buone librerie.

Funzioni di ordine superiore

Una funzione di ordine superiore è quella che accetta un'altra funzione come argomento o restituisce una funzione (o entrambe).

Questo è comunemente fatto con lambdas, ad esempio quando si passa un predicato a una clausola LINQ Where:

var results = data.Where(p => p.Items == 0);

La clausola Where () potrebbe ricevere molti predicati diversi che gli conferiscono una notevole flessibilità.

Passare un metodo in un altro metodo è anche visto quando si implementa il modello di progettazione della strategia. Ad esempio, vari metodi di ordinamento potrebbero essere scelti e passati in un metodo di ordinamento su un oggetto in base ai requisiti in fase di esecuzione.

Collezioni immutabili

Il pacchetto System.Collections.Immutable NuGet offre classi di raccolta immutabili.

Creazione e aggiunta di elementi

var stack = ImmutableStack.Create<int>();
var stack2 = stack.Push(1); // stack is still empty, stack2 contains 1
var stack3 = stack.Push(2); // stack2 still contains only one, stack3 has 2, 1

Creare usando il costruttore

Alcune collezioni immutabili dispongono di una classe interna Builder che può essere utilizzata per creare a buon mercato istanze immutabili di grandi dimensioni:

var builder = ImmutableList.CreateBuilder<int>(); // returns ImmutableList.Builder
builder.Add(1);
builder.Add(2);
var list = builder.ToImmutable();

Creazione da un oggetto I esistente

var numbers = Enumerable.Range(1, 5);
var list = ImmutableList.CreateRange<int>(numbers);

Elenco di tutti i tipi di raccolta immutabili:



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow