Pourquoi sont délégués types de référence?

Note rapide sur la accepté de répondre à: je suis en désaccord avec une petite partie de Jeffrey répondre, à savoir le point que depuis Delegate devait être un type de référence, il s'ensuit que tous les délégués sont des types référence. (Il n'est tout simplement pas vrai qu'un multi-niveau de la chaîne d'héritage sur les règles types de valeur; tous les types d'énumérations, par exemple, hériter de System.Enum, qui hérite de System.ValueType, qui hérite de l' System.Object, tous types de référence.) Cependant, je pense que le fait que, fondamentalement, tous les délégués en fait hériter pas seulement de Delegate mais de MulticastDelegate est la critique de la réalisation ici. Comme Raymond souligne dans un commentaire à son réponse, une fois que vous avez déterminé à soutenir plusieurs abonnés, il n'y a vraiment aucun point en pas à l'aide d'un type de référence pour le délégué lui-même, compte tenu de la nécessité d'un tableau quelque part.


Voir mise à jour en bas.

Il a toujours semblé étrange pour moi que si je fais ceci:

Action foo = obj.Foo;

Je suis entrain de créer un nouveau Action objet, à chaque fois. Je suis sûr que le coût est minime, mais il implique une allocation de la mémoire pour plus tard être nettoyée.

Donné que les délégués sont intrinsèquement eux-mêmes immuable, je me demande pourquoi ils ne pouvaient pas être des types de valeur? Puis une ligne de code comme celui ci-dessus entraînerait rien de plus qu'une simple affectation d'une adresse de mémoire sur la pile*.

Même en tenant compte des fonctions anonymes, il me semble (à moi) ce serait le travail. Considérons l'exemple simple suivant.

Action foo = () => { obj.Foo(); };

Dans ce cas foo ne constitue pas un fermeture, oui. Et dans de nombreux cas, j'imagine que cela ne nécessite une réelle type de référence (comme lorsque les variables locales sont fermés et sont modifiés à l'intérieur de la fermeture). Mais dans certains cas, il ne devrait pas. Par exemple, dans le cas ci-dessus, il semble qu'un type à l'appui de la fermeture pourrait ressembler à ceci: je reprends mon premier point à ce sujet. Le ci-dessous n'a vraiment besoin d'être un type de référence (ou: il n'a pas besoin être, mais si c'est un struct il va juste pour obtenir la boîte de toute façon). Donc, le mépris de l'exemple de code ci-dessous. Je le laisse seul à fournir un contexte pour les réponses le specfically le mentionner.

struct CompilerGenerated
{
    Obj obj;

    public CompilerGenerated(Obj obj)
    {
        this.obj = obj;
    }

    public void CallFoo()
    {
        obj.Foo();
    }
}

//...elsewhere...

//This would not require any long-term memory allocation
//if Action were a value type, since CompilerGenerated
//is also a value type.
Action foo = new CompilerGenerated(obj).CallFoo;

Cette question de sens? Comme je le vois, il y a deux explications possibles:

  • La mise en œuvre de délégués correctement comme des types de valeur aurait nécessité un travail supplémentaire ou de la complexité, puisque le soutien pour des choses comme des fermetures qui ne modifier les valeurs des variables locales aurait exigé généré par le compilateur types de référence, de toute façon.
  • Il y a quelques autres raisons pour lesquelles, sous le capot, les délégués ont simplement ne peut pas être mis en œuvre comme des types de valeur.

En fin de compte, je ne suis pas de perdre le sommeil plus de cela; c'est juste quelque chose que je ai été curieux de connaître un peu de temps.


Mise à jour: En réponse à l'Ani du commentaire, je ne vois pourquoi le CompilerGenerated type dans mon exemple ci-dessus pourrait tout aussi bien être un type de référence, car si un délégué va se composent d'un pointeur de fonction et d'un pointeur d'objet c'aurez besoin d'un type de référence, de toute façon (au moins pour les fonctions anonymes en utilisant les fermetures, car même si vous avez mis en place un supplément de paramètre de type générique—par exemple, Action<TCaller>—ce ne serait pas des types de couvert qui ne peuvent pas être nommés!). Cependant, tout cela est une sorte de me faire regretter d'amener la question de l'généré par le compilateur types de fermetures dans le débat à tous! Ma principale question est à propos de délégués, c'est à dire, la chose avec le pointeur de fonction et le pointeur d'objet. Il semble encore pour moi que pourrait être un type de la valeur.

En d'autres termes, même si cette...

Action foo = () => { obj.Foo(); };

...nécessite la création de un de référence de type object (à l'appui de la fermeture, et de donner le délégué quelque chose de référence), pourquoi faut-il de la création de deux (la fermeture-le soutien de l'objet plus la Action délégué)?

*Oui, oui, la mise en œuvre du détail, je sais! Tout ce que je veux dire, c'est à court terme de la mémoire de stockage.

  • La première explication possible des sons plus que de raison suffisante pour moi.
  • Ok, disons que vous souhaitez mettre en œuvre un délégué comme une valeur de type avec un pointeur de fonction et d'un pointeur d'objet. Dans votre fermeture exemple, où serait le pointeur d'objet point d'? Vous serait presque certainement besoin de cocher la CompilerGenerated struct exemple et le mettre sur le tas (avec évacuation d'analyse, ce qui pourrait être évitée dans certains cas).
  • Ah, je vois votre point de vue. Vous pourriez peut-être développer ce commentaire dans le formulaire de réponse?
  • Avez-vous vraiment envie de travailler avec des valeurs null<Action> ?
  • Avez-vous vraiment envie de travailler avec null? La possibilité de valeur null n'est pas toujours souhaité.
  • Jon Skeet a répondu ceci : stackoverflow.com/questions/2324224/...
  • Si un délégué est une structure qui contient un pointeur de fonction et pointeur d'objet, la construction d'une clôture ne nécessiterait la création d'un nouveau segment de l'objet plutôt que deux. Si les délégués étaient des types d'interface (qui est ce que je pense qu'ils devraient être), une clôture ne nécessiterait la création d'un unique objet tas de tenir à la fois la fermeture de données et de sa méthode.

InformationsquelleAutor Dan Tao | 2011-10-26