Recherche…


Func et Action

Func fournit un support pour les fonctions anonymes paramétrées. Les principaux types sont les entrées et le dernier type est toujours la valeur de retour.

// 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))

Les objets d' action sont comme des méthodes vides, ils n'ont donc qu'un type d'entrée. Aucun résultat n'est placé sur la pile d'évaluation.

// 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'imputabilité est courante dans la programmation fonctionnelle et rare dans la programmation orientée objet.

Créez, par exemple, un type d'adresse avec un état mutable:

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

Tout morceau de code pourrait altérer toute propriété de l'objet ci-dessus.

Créez maintenant le type d'adresse immuable:

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;
    }
}

Gardez à l’esprit qu’avoir des collections en lecture seule ne respecte pas l’immutabilité. Par exemple,

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

n'est pas immuable, car l'utilisateur de l'objet peut modifier la collection (ajouter ou supprimer des éléments). Pour le rendre immuable, il faut soit utiliser une interface comme IEnumerable, qui n'expose pas de méthodes à ajouter, soit en faire une 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());   

Avec l'objet immuable, nous avons les avantages suivants:

  • Il sera dans un état connu (autre code ne peut pas le changer).
  • C'est thread-safe.
  • Le constructeur offre un lieu unique pour la validation.
  • Savoir que l'objet ne peut pas être modifié rend le code plus facile à comprendre.

Éviter les références nulles

Les développeurs C # ont beaucoup d'exceptions de référence à traiter. Les développeurs F # ne le font pas car ils ont le type Option. Un type Option <> (certains préfèrent peut-être <> comme nom) fournit un type de retour Some et a None. Il est explicite qu'une méthode est sur le point de retourner un enregistrement nul.

Par exemple, vous ne pouvez pas lire ce qui suit et savoir si vous devrez gérer une valeur nulle.

var user = _repository.GetUser(id);

Si vous connaissez le possible null, vous pouvez introduire un code standard pour le gérer.

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

Que se passe-t-il si une option <> est retournée à la place?

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

Le code rend maintenant explicite le fait que nous pouvons avoir un enregistrement None et le code passe-partout pour vérifier certains ou aucun est requis:

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

La méthode suivante montre comment retourner une option <>

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>();
}

Voici une implémentation minimale d'Option <>.

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);
    }
}

Pour démontrer ce qui précède, AvoidNull.csx peut être exécuté avec le C # REPL.

Comme indiqué, il s'agit d'une implémentation minimale. Une recherche de paquets "Maybe" NuGet permettra de créer un certain nombre de bonnes bibliothèques.

Fonctions d'ordre supérieur

Une fonction d'ordre supérieur est une fonction qui prend une autre fonction en tant qu'argument ou retourne une fonction (ou les deux).

Cela se fait généralement avec lambdas, par exemple lors du passage d’un prédicat à une clause LINQ Where:

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

La clause Where () pourrait recevoir de nombreux prédicats différents, ce qui lui confère une flexibilité considérable.

Le passage d'une méthode à une autre méthode est également visible lors de la mise en œuvre du modèle de conception de stratégie. Par exemple, différentes méthodes de tri peuvent être choisies et passées dans une méthode de tri sur un objet en fonction des exigences lors de l'exécution.

Collections immuables

Le package System.Collections.Immutable NuGet fournit des classes de collection immuables.

Créer et ajouter des éléments

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

Création à l'aide du constructeur

Certaines collections immuables ont une classe interne Builder qui peut être utilisée pour créer à moindre coût de grandes instances immuables:

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

Créer à partir d'un IEnumerable existant

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

Liste de tous les types de collection immuables:



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow