206 votes

Obtenir la valeur d'une propriété dynamique c# via une chaîne de caractères

Je voudrais accéder à la valeur d'un fichier dynamic propriété c# avec une chaîne de caractères :

dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };

Comment puis-je obtenir la valeur de d.value2 ("random") si je n'ai que "value2" comme chaîne de caractères ? En javascript, je pourrais faire d["value2"] pour accéder à la valeur ("random"), mais je ne suis pas sûr de savoir comment le faire en c# et avec la réflexion. Voici ce que j'ai trouvé de plus proche :

d.GetType().GetProperty("value2") ... mais je ne sais pas comment en tirer la valeur réelle.

Comme toujours, merci pour votre aide !

30 votes

Notez que ce n'est pas le but recherché de "dynamic" et que ce scénario ne fonctionne pas mieux avec "dynamic" qu'avec "object". dynamic" permet d'accéder à des propriétés lorsque l'objet "objet" n'est pas disponible. nom de la propriété est connue au moment de la compilation mais le type ne l'est pas. Comme vous ne connaissez ni le nom ni le type au moment de la compilation, la dynamique ne vous sera d'aucune utilité.

0 votes

Possiblement lié : stackoverflow.com/questions/5877251/ .

3 votes

@EricLippert Je sais que cette question est ancienne mais juste pour faire un commentaire au cas où quelqu'un la verrait dans le futur. Dans certains cas, vous ne pouvez pas choisir d'utiliser la dynamique ou l'objet (par exemple, lorsque vous utilisez l'analyseur syntaxique JSON) et vous pouvez toujours vouloir obtenir les propriétés d'une chaîne (d'un fichier de configuration, par exemple), donc cette utilisation n'est pas aussi inhabituelle qu'on pourrait le penser.

260voto

Adam Robinson Points 88472

Une fois que vous avez votre PropertyInfo (de GetProperty ), vous devez appeler GetValue et passez l'instance dont vous voulez obtenir la valeur. Dans votre cas :

d.GetType().GetProperty("value2").GetValue(d, null);

5 votes

Je reçois un 'd.GetType().GetProperty("value2").GetValue(d)' threw an exception of type 'System.Reflection.TargetInvocationException' dynamic {System.Reflection.TargetInvocationException} dans la fenêtre de la montre avec ce

6 votes

Pensez que GetValue a besoin d'un paramètre supplémentaire - par exemple, d.GetType().GetProperty("value2").GetValue(d, null)

0 votes

Adam, tu avais raison avec Dommer's ,null cela a fonctionné correctement...merci pour votre aide.

41voto

IllidanS4 Points 811
public static object GetProperty(object target, string name)
{
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
    return site.Target(site, target);
}

Ajoutez une référence à Microsoft.CSharp. Fonctionne également pour les types dynamiques et les propriétés et champs privés.

Modifier : Bien que cette approche fonctionne, il existe une méthode presque 20× plus rapide du Microsoft.VisualBasic.dll montage :

public static object GetProperty(object target, string name)
{
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}

2 votes

Je voulais juste mentionner que la version VisualBasic n'est pas équivalente à votre version originale 'GetProperty' (le GetProperty invoque en fait le GetMember dynamique, qui fonctionne même sur les objets Python dans IronPython).

0 votes

1 cela fonctionnait pour les propriétés privées alors que FastMember et HyperDescriptor ne pouvaient pas le faire.

0 votes

@IllidanS4 quand vous avez comparé les CallSite code vs. CallByName code avez-vous comparé les deux en mettant en cache le CallSite instance ? Je soupçonne que le coût de votre première méthode est presque uniquement l'activation de l'option Binder y CallSite et non l'invocation de Target()

28voto

jbtule Points 11159

Dynamitey est un logiciel libre .net std qui vous permet de l'appeler comme la bibliothèque dynamic mais en utilisant une chaîne de caractères pour le nom de la propriété au lieu que le compilateur le fasse pour vous, et cela finit par être égale à la vitesse de réflexion (ce qui est loin d'être aussi rapide que l'utilisation du mot-clé dynamic, mais cela est dû à la surcharge de la mise en cache dynamique, là où le compilateur met en cache statiquement).

Dynamic.InvokeGet(d,"value2");

9voto

Francis Norton Points 167

La plupart du temps, lorsque vous demandez un objet dynamique, vous obtenez un ExpandoObject (pas dans l'exemple anonyme-mais-statique de la question ci-dessus, mais vous mentionnez JavaScript et mon analyseur JSON JsonFx, par exemple, génère des ExpandoObjects).

Si votre dynamique est en fait un ExpandoObject, vous pouvez éviter la réflexion en la transformant en IDictionary, comme décrit à l'adresse suivante http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx .

Une fois que vous avez effectué un cast vers IDictionary, vous avez accès à des méthodes utiles comme .Item et .ContainsKey.

0 votes

Malheureusement, le fait de devoir effectuer un cast vers IDictionary et d'utiliser TryGetValue, par exemple, a pour conséquence de renvoyer un vieil objet ordinaire. Vous ne pouvez pas tirer parti des opérateurs implicites à ce stade, car ils ne sont pris en compte qu'au moment de la compilation. Par exemple, si j'avais une classe Int64Proxy avec conversion implicite en Int64 ? Int64? i = data.value; //data is ExpandoObject rechercherait et appellerait automatiquement l'opérateur implicite. D'un autre côté, si je devais utiliser IDictionary pour tester l'existence du champ "value", je recevrais en retour un objet qui ne sera pas converti sans erreur en Int64 ?

5voto

James Gaunt Points 9541

d.GetType().GetProperty("value2")

renvoie un objet PropertyInfo.

Alors, faites

propertyInfo.GetValue(d)

3 votes

Merci, c'était la bonne réponse, mais comme mentionné plus haut, les GetValue(d) doit être GetValue(d,null)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X