2016-08-10 1 views
0

J'essaie de donner un sens aux délégués et aux expressions lambda et je lisais certaines des questions ici sur stackoverflow et j'ai atterri sur ce post où le deuxième exemple in this comment m'a complètement perdu. La première chose qui m'embrouille est le paramètre list qui n'est défini nulle part (je comprends que c'est le paramètre d'entrée du type return mais je trouve difficile de donner un sens à ce code) mais je pense que tout serait beaucoup plus clair une telle définition pourrait être utilisée dans la pratique (et c'est la deuxième chose que j'ai du mal à saisir).Méthodes qui retournent un délégué

Comment des méthodes telles que celles-ci pourraient-elles être utilisées dans la pratique?

public Func<IList<T>, T> SelectionMethod<T>() 
{ 
    return list => list.First(); 
} 

public Func<float, float> QuadraticFunctionMaker(float a , float b , float c) 
{ 
    return (x) => { return a * x * x + b * x + c; }; 
} 

Répondre

1

Les paramètres sont définis, c'est juste que leurs types sont déduits. La définition de l'argument est la partie avant le => - list (inféré comme étant de type IList<T>) et x (inféré comme étant de type float) respectivement dans vos exemples.

Le premier délégué correspond à une signature de:

T SomeMethod<T>(IList<T> list) 

Le second est:

float SomeMethod(float x) 

Depuis le compilateur sait ce que la signature du délégué doit être, il peut déduire les types requis automatiquement. Si vous deviez écrire le délégué en utilisant l'ancienne école syntaxe explicite, il ressemblerait à quelque chose comme ceci:

return (Func<IList<T>, T>)(delegate (IList<T> list) { return list.First(); }); 

Si vous voulez vraiment utiliser le typage explicite, vous pouvez spécifier les types au besoin:

(IList<T> list) => list.First() 

Lorsque vous voulez vraiment invoquer le délégué, vous devez passer l'argument, par exemple:

SelectionMethod<string>()(new List<string>()) 

la première expression lambda est très simple. La seconde se ferme en outre sur les arguments de la fonction "creator", ce qui signifie que vous pouvez accéder aux arguments du "créateur" dans le corps du délégué. Ceci est entièrement sûr dans un code purement immuable, mais cela peut être délicat si vous avez affaire à des types de références et à des effets secondaires modifiables - assurez-vous de bien comprendre la sémantique avant de faire quelque chose de fou avec ceux-ci. En fonction de votre expérience avec la programmation fonctionnelle, il peut être utile de réaliser que tout ceci n'est que de la supercherie de compilateurs. Les deux méthodes compileront à l'équivalent de quelque chose comme ceci:

public Func<IList<T>, T> SelectionMethod<T>() 
{ 
    return new Func<IList<T>, T>(__HiddenAnonymousMethod); 
} 

private T __HiddenAnonymousMethod<T>(IList<T> list) 
{ 
    return list.First(); 
} 

Le deuxième exemple est plus complexe en raison de la fermeture - nous avons besoin de créer un « objet d'aide » pour tenir les habitants capturés:

private class __HiddenAnonymousClass 
{ 
    float a, b, c; 

    public __HiddenAnonymousClass(float a, float b, float c) 
    { 
    this.a = a; this.b = b; this.c = c; 
    } 

    public float __HiddenAnonymousMethod(float x) 
    { 
    return a * x * x + b * x + c; 
    } 
} 

public Func<float, float> QuadraticFunctionMaker(float a , float b , float c) 
{ 
    return new Func<float, float> 
    (new __HiddenAnonymousClass(a, b, c).__HiddenAnonymousMethod); 
} 
+0

Bonne explication. Je trouve toute cette nouvelle syntaxe de plus en plus cryptique et j'ai tendance à éviter dans mon code les raccourcis syntaxiques, je pense qu'ils rendent le code beaucoup moins lisible. – Stefano