2009-12-02 3 views
0

Possible en double:
Finding the Variable Name passed to a Function in C#Comment faire pour convertir le nom de variable en chaîne dans C# .net?

public new Dictionary<string, string> Attributes { get; set; } 
public string StringAttributes = string.Empty; 

public int? MaxLength { get; set; } 
public int? Size { get; set; } 
public int? Width { get; set; } 
public int? Height { get; set; } 

protected override void OnInit(EventArgs e) { 
    Attributes = new Dictionary<string, string>(); 
    Attributes.Add("MaxLength", MaxLength.ToString()); 
    Attributes.Add("Size", Size.ToString()); 
    Attributes.Add("Width", Width.ToString()); 
    Attributes.Add("Height", Height.ToString()); 
    base.OnInit(e); 
} 

protected override void OnPreRender(EventArgs e) { 
    if (Attributes != null) { 
     StringBuilder attributes = new StringBuilder(); 
     foreach (var item in Attributes) { 
      if (!string.IsNullOrWhiteSpace(item.Value)) { 
       attributes.Append(item.Key + "=\"" + item.Value + "\" "); 
      } 
     } 
     StringAttributes = attributes.ToString(); 
    } 
} 

Le problème est ici, au lieu d'utiliser Attributes.Add("MaxLength", MaxLength.ToString()); et répétez le même processus pour d'autres propriétés, pourrait-on pas seulement une fonction qui est également en mesure d'ajouter des valeurs au dictionnaire, où les clés à ajouter sont leurs noms de variables? Say,

public void addAttribute(object variable){ 
    Attributes = new Dictionary<string, string>(); 
    Attributes.Add(variable.Name, variable.Value); 
}... 

Je suppose que cela est également possible de faire avec la réflexion, obtenir toutes les propriétés et nullables en boucle à travers eux puis en ajoutant chacun au dictionnaire ... Mais aussi longtemps que il y a d'autres façons, nous ne nous en tiendrions pas à la réflexion.

Mais si la réflexion est le seul choix, puis un autre problème serait maintenant comment obtenir les propriétés nullables de la classe ...

Toute aide serait grandement apprécié. Je vous remercie.

+1

Jetez un oeil à http://stackoverflow.com/questions/72121/finding-the-variable-name-passed-to-a-function-in-c – adrianbanks

+0

Je ne savais pas que nous pourrions utiliser des expressions pour cela ... ' chaîne publique GetPropertyName (Expression > variable) { return (variable.Body comme MemberExpression) .Member.Name; } ' – Jronny

+0

Oui, cette question a été posée ici plus d'une fois. Voici un autre lien: http://stackoverflow.com/questions/1669016/how-do-you-get-a-c-property-name-as-a-string-with-reflection –

Répondre

3

Je ne peux pas penser à la manière de le faire sans réflexion.

Afin d'obtenir toutes les propriétés nullables vous pouvez vous un code similaire à ceci:

GetType().GetProperties() 
     .Where(property => 
      property.PropertyType.IsGenericType && 
      property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) 

Exemple d'utilisation qui remplit les attributs dictionnaire:

PropertyInfo[] typeProperties = GetType().GetProperties(); 
var nullableProperties = typeProperties.Where(property => 
    property.PropertyType.IsGenericType && 
    property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)); 

var attributes = new Dictionary<string, string>(); 
foreach (var nullableProperty in nullableProperties) 
{ 
    object value = nullableProperty.GetValue(this,null); 
    attributes.Add(nullableProperty.Name, value == null ? 
               string.Empty : value.ToString()); 
} 
+0

merci ... mais mon problème est maintenant comment obtenir la valeur foreach (var item dans typeProperties) { Attributes.Add (item.Name, item. * Ne peut pas obtenir la valeur ici *); } – Jronny

+0

Remplacé l'exemple d'utilisation par quelque chose de similaire qui remplit les attributs dans le dictionnaire :) – Elisha

+0

Merci. Je vais essayer plus tard. – Jronny

2

Je ne suis pas sûr que je comprends parfaitement votre question sans plus de contexte, mais peut-être cela est-il utile

Si le problème concerne le surdébit de réflexion pour les appels multiples:

  • Cache cette information.
  • essayer EmitMapper de remplir les valeurs
  • essayer AutoMapper de remplir les valeurs

Si le problème est d'obtenir un nom de variable via la compilation fortement typé, vous pouvez utiliser

La classe membre, j'ai vu sur un poste de Oliver Hhanappi. Des exemples de son utilisation sont ici sur mon blog

+0

Je pourrais avoir besoin d'utiliser cela un jour. – Jronny

+0

lequel est-ce? J'ai donné 4 solutions possibles/idées – Maslow

+0

Mise en cache d'informations ... Mais les autres pourraient aussi être utiles un jour. Merci. – Jronny

1

Vous pouvez utiliser la fonction suivante pour extraire les propriétés publiques Nullable d'une classe dans le format que vous recherchez. Il appelle également la méthode getter pour la valeur.

Ceci utilise la même utilisation de réflexion dont a parlé @Elisha. Il effectue également un appel .ToString() à la valeur renvoyée par le getter.

IDictionary<string, string> GetProps<T>(T DataObject) 
{ 
    if(null == DataObject) 
     return new Dictionary<string, string>(); 
    var nullableProperties = 
     from property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public) 
     from accessor in property.GetAccessors(false) 
     let returnType = accessor.ReturnType 
     where returnType.IsGenericType 
     && returnType.GetGenericTypeDefinition() == typeof(Nullable<>) 
     && accessor.GetParameters().Length == 0 
     select new { Name=property.Name, Getter=accessor}; 
    return nullableProperties.ToDictionary(
     x => x.Name, 
     x => x.Getter.Invoke(DataObject, null).ToString()); 
} 
1

Voici ma solution complète. Je dirais que votre meilleur pari est d'utiliser la réflexion, car ce que vous demandez est en quelque sorte une méta-tâche.En ce qui concerne la façon dont vous savez quelles propriétés ajouter, je suggérerais de définir votre propre attribut et de l'appliquer aux champs/propriétés que vous voulez inspecter.

Utilisation:

Dictionary<string, string> attributes = Inspector<MyClass>.Inspect(target); 

La réflexion dans mon exemple de code est exécuté une fois par type inspecté, il est exécuté dans le constructeur statique de ma classe générique Vérifiez:

// apply this attribute to any properties or fields that you want added to the attributes dictionary 
[AttributeUsage(
    AttributeTargets.Property | 
    AttributeTargets.Field | 
    AttributeTargets.Class | 
    AttributeTargets.Struct | 
    AttributeTargets.Interface, 
    AllowMultiple = true, Inherited = true)] 
public class InspectAttribute : Attribute 
{ 
    // optionally specify the member name explicitly, for use on classes, structs, and interfaces 
    public string MemberName { get; set; } 

    public InspectAttribute() { } 

    public InspectAttribute(string memberName) 
    { 
     this.MemberName = memberName; 
    } 
} 

public class Inspector<T> 
{ 
    // Inspector is a generic class, therefore there will be a separate instance of the _InspectActions variable per type 
    private static List<Action<Dictionary<string, string>, T>> _InspectActions; 

    static Inspector() 
    { 
     _InspectActions = new List<Action<Dictionary<string, string>, T>>(); 
     foreach (MemberInfo m in GetInspectableMembers(typeof(T))) 
     { 
      switch (m.MemberType) 
      { 
       case MemberTypes.Property: 
        { 
         // declare a separate variable for variable scope with anonymous delegate 
         PropertyInfo member = m as PropertyInfo; 
         // create an action delegate to add an entry to the attributes dictionary using the property name and value 
         _InspectActions.Add(
          delegate(Dictionary<string, string> attributes, T item) 
          { 
           object value = member.GetValue(item, null); 
           attributes.Add(member.Name, (value == null) ? "[null]" : value.ToString()); 
          }); 
        } 
        break; 
       case MemberTypes.Field: 
        { 
         // declare a separate variable for variable scope with anonymous delegate 
         FieldInfo member = m as FieldInfo; 
         // need to create a separate variable so that delegates do not share the same variable 
         // create an action delegate to add an entry to the attributes dictionary using the field name and value 
         _InspectActions.Add(
          delegate(Dictionary<string, string> attributes, T item) 
          { 
           object value = member.GetValue(item); 
           attributes.Add(member.Name, (value == null) ? "[null]" : value.ToString()); 
          }); 
        } 
        break; 
       default: 
        // for all other member types, do nothing 
        break; 
      } 
     } 
    } 

    private static IEnumerable<MemberInfo> GetInspectableMembers(Type t) 
    { 
     // get all instance fields and properties 
     foreach (MemberInfo member in t.GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.GetField | BindingFlags.GetProperty)) 
     { 
      // check if the current member is decorated with an Inspect attribute 
      object[] inspectAttributes = member.GetCustomAttributes(typeof(InspectAttribute), true); 
      if (inspectAttributes != null && inspectAttributes.Length > 0) 
      { 
       yield return member; 
      } 
     } 

     // now look for any Inspect attributes defined at the type level 
     InspectAttribute[] typeLevelInspectAttributes = (InspectAttribute[])t.GetCustomAttributes(typeof(InspectAttribute), true); 
     if (typeLevelInspectAttributes != null && typeLevelInspectAttributes.Length > 0) 
     { 
      foreach (InspectAttribute attribute in typeLevelInspectAttributes) 
      { 
       // search for members matching the name provided by the Inspect attribute 
       MemberInfo[] members = t.GetMember(attribute.MemberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.FlattenHierarchy); 

       if (members != null && members.Length > 0) 
       { 
        foreach (MemberInfo member in members) 
        { 
         yield return member; 
        } 
       } 
      } 
     } 
    } 

    public static Dictionary<string, string> Inspect(T item) 
    { 
     // create a new attributes dictionary 
     Dictionary<string, string> attributes = new Dictionary<string, string>(); 
     foreach (Action<Dictionary<string, string>, T> inspectAction in _InspectActions) 
     { 
      // execute each "inspect" action. 
      // This will execute the delegates we created earlier, causing entries to be added to the dictionary 
      inspectAction(attributes, item); 
     } 
     return attributes; 
    } 
} 

public class BasePage 
{ 
    public int? SomeValue { get; set; } 
} 

// example class with properties decorated with the Inspect attribute 
[Inspect("SomeValue")] // also inspect the "SomeValue" property from the BasePage class 
public class MyPage : BasePage 
{ 
    [Inspect] 
    public int? MaxLength { get; set; } 
    [Inspect] 
    public int? Size { get; set; } 
    [Inspect] 
    public int? Width { get; set; } 
    [Inspect] 
    public int? Height { get; set; } 

    public string GenerateAttributeString() 
    { 
     System.Text.StringBuilder attributes = new System.Text.StringBuilder(); 
     foreach (KeyValuePair<string, string> item in Inspector<MyPage>.Inspect(this)) 
     { 
      attributes.Append(item.Key + "=\"" + item.Value + "\" "); 
     } 
     return attributes.ToString(); 
    } 
} 
Questions connexes