2009-12-21 5 views
0

J'ai quelques doutes sur le titre, mais je n'ai rien trouvé de mieux.Obtention d'une propriété à partir d'une représentation

Dire que j'ai le ENUM suivant

public enum ClassProperties 
{ 
    Primary = 0, 
    Secondary = 1, 
} 

Et une classe qui ressemble cela maintenant quelque part

public class Test 
{ 
    Primary { get { return _primary; }} 
    Secondary { get { return _secondary; }} 
    // more irrelevant properties 
} 

le long de la ligne que je dois itérer sur l'énumération et utiliser chaque élément pour obtenir la propriété, comme ainsi:

foreach(ClassProperties myProp = Enum.GetValues(typeof(ClassProperties))) 
{ 
    Test t = new Test(); 
    t.myProp // <- this is what I'm after 
    // so if myProp equals Primary, 
    // t.Primary is called... 
} 

Ceci te donnerait une idée de ce que j'essaye de faire, mais tr ying me fait me sentir sale comme un clochard qui vient de se mouiller. Cela ne me semble pas juste.

+0

La réflexion ne serait-elle pas meilleure? –

+1

Je ne sais pas ce que vous cherchez ici. Au lieu de la solution proposée, pourriez-vous expliquer le problème que vous essayez de résoudre? –

+0

Sont-ils tous du même type? Si c'est le cas, un Dictionary pourrait convenir. – AakashM

Répondre

2

Eh bien, vous pourriez utiliser la réflexion pour récupérer les propriétés. Cela permettra ensuite de localiser la propriété en fonction de son nom.

Test t = new Test(); 
Type testType = t.GetType(); 
PropertyInfo[] properties = testType.GetProperties(); 

Pour plus voir GetProperties() method & le retour de type PropertyInfo.

+0

Très bien, je vais plonger dans la réflexion alors :) – Oxymoron

+0

La réflexion est assez simple quand on y entre. C'est assez puissant bien que vous subissiez un léger coup de performance. Pour la majorité des cas, cela ne devrait pas poser de problème. – Ian

+0

Ouais, déjà réparé :), je suis encore tout à fait nouveau pour cela :) – Oxymoron

0

L'énumération et les propriétés associées sont-elles dynamiques? Si c'est le cas, vous voudrez utiliser la réflexion. Sinon, vous pourriez faire une simple déclaration if-then.

2
foreach(ClassProperties myProp in Enum.GetValues(typeof(ClassProperties))) 
{ 
    Test t = new Test(); 
    PropertyInfo prop = typeof(Test).GetProperty(myProp.ToString()); 
    // Get 
    object value = prop.GetValue(t, null); 
    // Set 
    prop.SetValue(t, newValue, null); 
} 
0

Il y a au moins deux façons de le faire:

1.Reflection et PropertyInfo

var obj = new TestClass(); 
var allProps = typeof(TestClass).GetProperties(); 
foreach (var prop in allProps) 
{ 
    // Get propertie value 
    object propValue = prop.GetGetMethod().Invoke(obj, null); 
    //Set propertie value 
    prop.GetSetMethod().Invoke(obj, new object[] { propValue }); 
} 

Vous devez être prudent en ce qui concerne la performance si, à rude épreuve pour une classe avec deux propriétés de réglage et d'obtenir toutes les propriétés 10k fois prend 0,06 secondes avec réflexion et 0,001 secondes si je l'écris à la main. Donc la performance est assez drastique

2.Dynamic Methods Cette méthode est plus compliquée mais les performances en valent la peine. Les méthodes dynamiques sont des méthodes pour lesquelles le programme émet MSIL lors de l'exécution. Ils sont exécutés par le runtime comme s'ils avaient été créés par le compilateur (donc la vitesse est très bonne). L'utilisation de cette méthode et l'obtention de 2 propriétés sur une classe de 10k fois prenaient 0,004 secondes (comparé à 0,06 secondes avec réflexion et 0,001 seconde à la main). Bellow est le code pour générer un tableau de délégués pour les getters et setters pour un certain type. Générer la dynamique peut être coûteux, donc vous devriez mettre en cache les délégués si vous avez l'intention d'utiliser plusieurs fois (ce qui sera probablement le cas).

//Container for getters and setters of a property 
public class MyProp 
{ 
    public string PropName { get; set; } 
    public Func<object,object> Getter{get;set;} 
    public Action<object,object> Setter{get;set;} 
} 

public static MyProp[] CreatePropertyDelagates (Type type) 
{ 
     var allProps = type.GetProperties(); 
     var props = new MyProp[allProps.Length]; 

     for(int i =0;i<allProps.Length;i++) 
     { 
      var prop = allProps[i]; 
      // Getter dynamic method the signature would be : 
      // object Get(object thisReference) 
      // { return ((TestClass)thisReference).Prop; } 

      DynamicMethod dmGet = new DynamicMethod("Get", typeof(object), new Type[] { typeof(object), }); 
      ILGenerator ilGet = dmGet.GetILGenerator(); 
      // Load first argument to the stack 
      ilGet.Emit(OpCodes.Ldarg_0); 
      // Cast the object on the stack to the apropriate type 
      ilGet.Emit(OpCodes.Castclass, type); 
      // Call the getter method passing the object on the stack as the this reference 
      ilGet.Emit(OpCodes.Callvirt, prop.GetGetMethod()); 
      // If the property type is a value type (int/DateTime/..) box the value so we can return it 
      if (prop.PropertyType.IsValueType) 
      { 
        ilGet.Emit(OpCodes.Box, prop.PropertyType); 
      } 
      // Return from the method 
      ilGet.Emit(OpCodes.Ret); 


      // Setter dynamic method the signature would be : 
      // object Set(object thisReference, object propValue) 
      // { return ((TestClass)thisReference).Prop = (PropType)propValue; } 

      DynamicMethod dmSet = new DynamicMethod("Set", typeof(void), new Type[] { typeof(object), typeof(object) }); 
      ILGenerator ilSet = dmSet.GetILGenerator(); 
      // Load first argument to the stack and cast it 
      ilSet.Emit(OpCodes.Ldarg_0); 
      ilSet.Emit(OpCodes.Castclass, type); 

      // Load secons argument to the stack and cast it or unbox it 
      ilSet.Emit(OpCodes.Ldarg_1); 
      if (prop.PropertyType.IsValueType) 
      { 
        ilSet.Emit(OpCodes.Unbox_Any,prop.PropertyType); 
      } 
      else 
      { 
        ilSet.Emit(OpCodes.Castclass, prop.PropertyType); 
      } 
      // Call Setter method and return 
      ilSet.Emit(OpCodes.Callvirt, prop.GetSetMethod()); 
      ilSet.Emit(OpCodes.Ret); 

      // Create the delegates for invoking the dynamic methods and add the to an array for later use 
      props[i] = new MyProp() 
      { 
        PropName = prop.Name, 
        Setter = (Action<object, object>)dmSet.CreateDelegate(typeof(Action<object, object>)), 
        Getter = (Func<object, object>)dmGet.CreateDelegate(typeof(Func<object, object>)), 
      }; 

     } 
     return props; 
} 

des méthodes Invocation dynamiques:

// Should be cahced for further use 
var testClassProps = CreatePropertyDelagates(typeof(TestClass)); 

var obj = new TestClass(); 
foreach (var p in testClassProps) 
{ 
     var propValue = p.Getter(obj); 
     p.Setter(obj,propValue); 
} 

Obs: Le code ci-dessus traite pas avec des propriétés qui n'ont pas getter ou pas setter ou sont privées. Cela pourrait être facilement fait en regardant les propriétés de la classe ProperyInfo et en ne créant que les délégués si cela est approprié.

Questions connexes