J'ai une méthode qui accepte une expression Je peux le faire fonctionner pour des références de propriété directe, donc si je passe dans l'expression Cependant, je ne peux pas le faire travailler pour des expressions arbitraires. Par exemple, si l'expression est Comment puis-je regarder l'instance d'expression spécifique et dériver le type de retour réel? P>
objet code>. P>
x => x.integerproperty code> je peux obtenir une référence de type pour un entier. Cette approche nécessite de la convertir en une mémorexion. P>
x => x.integerproperty.tostring () code> je veux obtenir une référence de type pour une chaîne. Je ne peux pas compiler cela à une mémorexion, et si je viens de
.Compile () code> et vérifier le type de retour que j'obtiens "objet". P>
3 Réponses :
Bien que pas impossible, c'est particulièrement difficile. Il faudrait marcher dans l'arbre d'expression et faire une logique potentiellement complexe. Par exemple, que voudriez-vous voir si je suis passé dans l'expression suivante? Cette méthode pourrait em> renvoyer un MAINTENANT, vous pourrez peut-être faire plus d'avance en déchargeant une partie de cette logique sur le compilateur. Vous pouvez modifier votre paramètre de méthode à partir de Bien sûr, dans le cas de mon exemple, vous travaillerez toujours contre int code> ou a
chaîne code>. p>
Func
Func
typeof (Treturn) code> dans la méthode Pour déterminer ce que le compilateur a décidé le type de retour de l'expression était. p>
objet code>. Mais, votre exemple de
x => x.integerproperty.tostring () code> donnera
string code>, ce que vous recherchez. P> p>
Vous faites de bons points, mais cela est utilisé dans certaines circonstances spécifiques où ces cas de bord ne devraient pas arriver (ou peuvent être facilement évités en les connaissant). Merci!
En fait, @adam Maras, votre exemple ne compilerait même jamais car l'opérateur ternaire lancerait une erreur d'heure de compilation disant "type d'expression conditionnelle ne peut pas être déterminé car il n'y a pas de conversion implicite entre" int 'et "chaîne" "
C'était plus d'exercice de pensée qu'un échantillon de code littéral.
Un peu d'une manière effrontée (et cela implique d'appeler réellement le Func code>), mais vous pouvez le faire:
using System;
class Program
{
static Func<T,object> MakeFunc<T>()
{
return x => 23;
}
static Type GetReturnType<T>(Func<T,object> f)
{
return f(default(T)).GetType();
}
static void Main(string[] args)
{
Type t = GetReturnType(MakeFunc<string>());
Console.WriteLine(t);
}
}
Je ne sais pas comment je me sens à propos de l'exécution de l'expression pour obtenir le type de retour; Et s'il y a des effets secondaires sur la fonction? Dans mon cas particulier qui n'est pas une grosse inquiétude, mais j'ai accepté une réponse qui semble fonctionner aussi bien et n'exige pas d'exécution. Merci quand même!
@Seth: Personnellement, je ne serais pas trop content de l'exécution de l'expression (c'est une limitation de l'approche) - c'était juste le meilleur que je puisse venir sur le dessus de ma tête. L'un des avantages de cette approche est que cela fonctionne sur FUNC code> des instances plutôt que sur
Expression code>.
quelque chose comme ça pourrait faire le tour. Cela ne couvre probablement pas toutes les possibilités, mais c'est un début.
public static Type GetObjectType<T>(Expression<Func<T, object>> expr) { if ((expr.Body.NodeType == ExpressionType.Convert) || (expr.Body.NodeType == ExpressionType.ConvertChecked)) { var unary = expr.Body as UnaryExpression; if (unary != null) return unary.Operand.Type; } return expr.Body.Type; }
Je ne pouvais penser à aucun autre type d'expression que cela pourrait éventuellement être si ce n'était pas réellement objet code>. Couvre tous les cas que je pouvais penser.
Travaillé grand. J'utilise cela dans un ensemble de circonstances assez spécifiques, donc si là sont i> des cas de bord que vous n'avez pas couvert ils ne me font pas encore de douleur. Merci!
N'est pas assez expr ..type assez? Je me manque mal lorsque vous utilisez le code ci-dessus avec, par exemple, i => (flotteur) i où je suis un entier. Ensuite, ce code retourne entier et ne pas flotter. Mais simplement expr.body.type fonctionne.
@Andreas: Êtes-vous sûr? Mon code ci-dessus renvoie correctement float code> lorsque je passe dans
(int i) => (float) i code>, alors que vous utilisez juste
expr.body.type code> renvoie
objet code>.
Techniquement, le type de retour réel de l'expression est ...
objet code>. Étant donné que la fonction était nécessaire pour renvoyer
objet code>, les expressions nécessaires ont été générées pour s'assurer que le type est renvoyé (une conversion dans ce cas).