Sök…


Func och action

Func tillhandahåller en hållare för parametriserade anonyma funktioner. De ledande typerna är ingångarna och den sista typen är alltid returvärdet.

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

Handlingsobjekt är som ogiltiga metoder så att de bara har en ingångstyp. Inget resultat placeras på utvärderingsstacken.

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

Oföränderlighet

Oändlighet är vanligt vid funktionell programmering och sällsynt i objektorienterad programmering.

Skapa till exempel en adresstyp med stängbart tillstånd:

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

Varje kodkod kan förändra egendom i ovanstående objekt.

Skapa nu den immutabla adresstypen:

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

Tänk på att det att ha skrivskyddade samlingar inte respekterar oföränderlighet. Till exempel,

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

är inte oföränderligt, eftersom användaren av objektet kan ändra samlingen (lägg till eller ta bort element från det). För att göra det obrukbart måste man antingen använda ett gränssnitt som IEnumerable, som inte avslöjar metoder för att lägga till, eller för att göra det till en 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());   

Med det immutable objektet har vi följande fördelar:

  • Den kommer att vara i känt tillstånd (annan kod kan inte ändra den).
  • Det är trådsäkert.
  • Konstruktören erbjuder en enda plats för validering.
  • Att veta att objektet inte kan ändras gör koden lättare att förstå.

Undvik nollreferenser

C # -utvecklare får många nullreferensundantag att hantera. F # -utvecklare gör inte för att de har typen Option. Ett alternativ <> -typ (en del föredrar kanske <> som namn) ger en typ och ingen-returtyp. Det gör det tydligt att en metod kan vara på väg att returnera en nollpost.

Till exempel kan du inte läsa följande och veta om du kommer att behöva hantera ett nollvärde.

var user = _repository.GetUser(id);

Om du känner till den möjliga nollan kan du introducera någon pannkodskod för att hantera den.

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

Tänk om vi har ett alternativ <> i stället?

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

Koden gör det nu tydligt att vi kan ha en Ingen-post returnerad och pannplattkoden för att kontrollera om någon eller ingen krävs:

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

Följande metod visar hur du returnerar ett alternativ <>

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

Här är en minimal implementering av alternativ <>.

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

För att demonstrera ovan kan prevent.Null.csx köras med C # REPL.

Som sagt är detta en minimal implementering. En sökning efter "Kanske" NuGet-paket kommer att visa upp ett antal bra bibliotek.

Funktioner med högre ordning

En funktion med högre ordning är en som tar en annan funktion som ett argument eller returnerar en funktion (eller båda).

Detta görs vanligtvis med lambdas, till exempel när man överför ett predikat till en LINQ Where-klausul:

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

Var () -klausulen kan få många olika predikat vilket ger den betydande flexibilitet.

Att överföra en metod till en annan metod ses också när man implementerar strategidesignmönstret. Till exempel kan olika sorteringsmetoder väljas från och överföras till en sorteringsmetod på ett objekt beroende på kraven vid körtid.

Oändliga samlingar

System.Collections.Immutable NuGet-paketet erbjuder immutable samlingsklasser.

Skapa och lägga till objekt

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

Skapa med hjälp av byggaren

Vissa immutable samlingar har en Builder inre klass som kan användas för att billigt bygga stora immutable instanser:

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

Skapa från en befintlig IEnumerable

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

Lista över alla oföränderliga samlingstyper:



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow