Vous pouvez obtenir un Func<T> (ou similaire) à partir d'un MethodInfo objet?
Je me rends compte que, de façon générale, il y a des implications sur les performances de l'utilisation de la réflexion. (Je me suis pas une fan de réflexion à tous, en fait; c'est une question purement académique.)
Supposons qu'il existe une certaine classe qui ressemble à ceci:
public class MyClass {
public string GetName() {
return "My Name";
}
}
Ours avec moi ici. Je sais que si j'ai une instance de MyClass
appelé x
, je peux appeler x.GetName()
. De plus, j'ai mis un Func<string>
variable x.GetName
.
Maintenant, voici ma question. Disons que je ne pas savoir la classe ci-dessus est appelé MyClass
; j'ai quelques objets, x
, mais je n'ai aucune idée de ce que c'est. J'ai pu vérifier pour voir si l'objet a une GetName
méthode en faisant ceci:
MethodInfo getName = x.GetType().GetMethod("GetName");
Supposons que getName
n'est pas nulle. Alors je n'ai pas pu en outre vérifier si getName.ReturnType == typeof(string)
et getName.GetParameters().Length == 0
, et à ce point, je ne serais pas tout à fait certain que la méthode représentée par mes getName
objet pourrait certainement être exprimées à une Func<string>
, en quelque sorte?
Je me rends compte il y a un MethodInfo.Invoke
, et je me rends compte aussi que je pourrais toujours créer un Func<string>
comme:
Func<string> getNameFunc = () => getName.Invoke(x, null);
Je crois que je vais poser est de savoir si il existe un moyen d'aller de un MethodInfo
objet à la méthode qu'il représente, d'encourir le coût de la réflexion dans le processus, mais après que point de pouvoir appeler la méthode directement (via, par exemple, un Func<string>
ou quelque chose de similaire) sans performances.
Ce que je suis à envisager pourrait ressembler à quelque chose comme ceci:
//obviously this would throw an exception if GetActualInstanceMethod returned
//something that couldn't be cast to a Func<string>
Func<string> getNameFunc = (Func<string>)getName.GetActualInstanceMethod(x);
(Je me rends compte qui n'existe pas; je me demandais si il n'y a rien comme il.)
- Sur les commentaires que vous faites dans votre travail d'édition - vous verrez une énorme augmentation de la vitesse avec des solutions de ce type, parce qu'il y a très peu de différence entre un compilé dynamiquement délégué et un compilés statiquement un; une fois la surcharge de la compilation est pris en compte. Depuis que j'ai "découvert" l'expression des arbres de choses, j'ai été en utilisant tous les sens, et sans doute que mon #1 fonction de .Net 3.5 . En v4, c'est encore mieux que vous pouvez écrire plusieurs instructions de code nécessaire à cause des extensions requises par le DLR.
Vous devez vous connecter pour publier un commentaire.
Ce genre de remplace ma précédente réponse, car ce, bien qu'il soit un peu plus de la route vous donne un rapide appel de méthode et, contrairement à certains des autres réponses, vous permet de passer à travers différentes instances (dans le cas où vous allez à la rencontre de plusieurs instances d'un même type). SI vous ne le souhaitez pas, cochez ma mise à jour en bas (ou regarder Ben M de la réponse).
Voici une méthode de test qui fait ce que vous voulez:
Une fois que vous générez le délégué une fois - vous pouvez mettre en cache dans un Dictionnaire:
Tout ce que vous faire est alors de l'ajouter au dictionnaire, à l'aide de l'entrant de Type de l'objet (à partir de GetType()) comme clé. Dans l'avenir, vous devez d'abord vérifier si vous avez un prêt-cuit délégué dans le dictionnaire (et à l'appeler si si), sinon vous construire d'abord, l'ajouter dans les, puis de l'appeler.
D'ailleurs, c'est un très très version simplifiée de la sorte de chose que la RDL ne pour la répartition dynamique du mécanisme (en C#, c'est lorsque vous utilisez la "dynamique" mot-clé).
Et enfin
Si, comme quelques personnes l'ont mentionné, tout simplement, vous voulez faire cuire un Func directement lié à l'objet que vous recevez ensuite vous faites cela:
Notez, cependant, qu'une fois l'expression de l'arbre se jette pas, vous devez vous assurer que le(Supprimé à la suite de Ben M commentaires)o
reste dans la portée, sinon, vous pourriez obtenir certains méchant résultats. Le plus simple serait de tenir un local de référence (dans une instance de classe, peut-être) pour la durée de vie de votre délégué.result
est en fait un délégué ciblant une instance deSystem.Runtime.CompilerServices.ExecutionScope
, dontGlobals
propriété contient une référence à l'objet d'origine (o
) -- donc il n'y a pas besoin de tenir une deuxième référence afin d'éviter le garbage collector.Func
, au lieu d'utiliser unDictionary
vous pouvez suivre le modèle de l'aide d'un génériques imbriqués statique de la classe comme dans Marc Gravel, en réponse à une autre question.Oui, c'est possible:
MethodInfo
. Si donc, en terme de performance que vous feriez mieux de faire GetName être statique et qui prend une référence à l'instance (de manière explicitethis
pointeur), résultant en unFunc<Foo, string
. En gros: ça dépend, YMMV.Voici ma réponse, par la construction d'une arborescence d'expression. Contrairement à d'autres réponses, le résultat (
getNameFunc
) est une fonction qui est lié à l'instance d'origine, sans avoir à passer comme paramètre.La façon la plus simple de le faire est par le biais de
Delegate.CreateDelegate
:Noter que cette lie
getNameFunc
àx
, de sorte que pour chaquex
vous auriez besoin de créer une nouvelle instance de délégué. Cette option est beaucoup moins compliqué que leExpression
basée sur des exemples. Cependant, avec l'Expression basée sur des exemples, il est possible de créer unFunc<MyClass, string> getNameFuncForAny
une fois, que vous pouvez réutiliser pour chaque instance d'unMyClass
.À créer un tel getNameFuncForAny, vous auriez besoin d'une méthode comme
que vous pouvez utiliser comme:
Si vous ne voulez pas être attaché à
Func<MyClass, string>
, vous pouvez définirDelegate.CreateDelegate (typeof (Func<MyClass, string>), getName)
-- je crois qu'il est appelé une "délégué".Vous pourriez construire une Arborescence d'Expression représentant un lambda de l'appel à cette méthode, puis
Compile()
de sorte que plus d'appels sera aussi rapide que la norme compilé des appels.Sinon, j'ai écrit cette méthode un bon moment, il ya appuie sur un article de MSDN, qui génère un wrapper utilisant IL de faire appel à d'
MethodInfo
manière plus rapide qu'avecMethodInfo.DynamicInvoke
car une fois le code généré, il n'y a presque pas de frais généraux au cours d'un appel normal.L'un sur le dessus de ma tête approche serait d'utiliser dynamique. Vous pouvez donc quelque chose comme ceci: