43 votes

Comment obtenir le nom actuel de la propriété par réflexion?

Je voudrais obtenir le nom de la propriété lorsque j'y suis via un mécanisme de réflexion. C'est possible?

Mise à jour: j'ai un code comme celui-ci:

     public CarType Car
    {
        get { return (Wheel) this["Wheel"];}
        set { this["Wheel"] = value; }
    }
 

Et parce que j'ai besoin de plus de propriétés comme celle-ci, je voudrais faire quelque chose comme ça:

     public CarType Car
    {
        get { return (Wheel) this[GetThisPropertyName()];}
        set { this[GetThisPropertyName()] = value; }
    }
 

57voto

RichardOD Points 19942

Puisque les propriétés sont vraiment juste des méthodes que vous pouvez le faire et de nettoyer le get_ retourné:

class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            var x = p.Something;
            Console.ReadLine();
        }

        public string Something
        {
            get
            {
                return MethodBase.GetCurrentMethod().Name;
            }
        }
    }

Si vous le profil de la performance, vous devriez trouver MethodBase.GetCurrentMethod() est à des lieues plus vite que la structure de pile. Dans .NET 1.1, vous aurez également des problèmes avec la structure de pile en mode release (de mémoire je crois que j'ai trouvé c'était 3x plus rapide).

Cela dit je suis sûr que le problème de performances ne cause pas trop de problème - si une discussion intéressante sur la structure de pile lenteur peut être trouvé ici.

J'imagine une autre option, si vous étiez préoccupé par le rendement serait de créer un Intellisense de Visual Studio Extrait de Code qui crée la propriété pour vous et aussi crée une chaîne qui correspond au nom de la propriété.

7voto

tvanfosson Points 268301

J'aimerais en savoir plus sur le contexte dans lequel vous en avez besoin, car il me semble que vous devriez déjà savoir ce que la propriété que vous travaillez dans la propriété de l'accesseur. Si vous devez, cependant, vous pourriez probablement utiliser MethodBase.GetCurrentMethod().Nom et enlever quoi que ce soit après l' get_/set_.

Mise à jour:

Basé sur vos modifications, je dirais que vous devriez utiliser l'héritage plutôt que de réflexion. Je ne sais pas quelles sont les données dans votre dictionnaire, mais il me semble que vous voulez vraiment avoir différentes catégories de Voitures, dire Berline, Cabriolet, Buggy, StationWagon, ne pas garder le type d'une variable locale. Ensuite, vous avez les implémentations de méthodes que de faire la bonne chose pour ce type de Voiture. Au lieu de trouver ce genre de voiture que vous avez, ensuite, de faire quelque chose, il vous suffit alors d'appeler la méthode appropriée et de l'objet Voiture fait la bonne chose en fonction du type il est.

 public interface ICar
 {
      void Drive( decimal velocity, Orientation orientation );
      void Shift( int gear );
      ...
 }

 public abstract class Car : ICar
 {
      public virtual void Drive( decimal velocity, Orientation orientation )
      {
          ...some default implementation...
      }

      public abstract void Shift( int gear );

      ...
 }

 public class AutomaticTransmission : Car
 {
       public override void Shift( int gear )
       {
          ...some specific implementation...
       }
 }

 public class ManualTransmission : Car
 {
       public override void Shift( int gear )
       {
          ...some specific implementation...
       }
 }

5voto

weiqure Points 2069

Utilisez plutôt MethodBase.GetCurrentMethod ()!

La réflexion est utilisée pour travailler avec des types qui ne peuvent pas être effectués au moment de la compilation. Obtenir le nom de l'accesseur de propriété dans lequel vous vous trouvez peut être décidé au moment de la compilation, vous ne devriez donc probablement pas utiliser la réflexion pour cela.

Vous pouvez cependant utiliser le nom de la méthode d'accesseur à partir de la pile d'appels en utilisant System.Diagnostics.StackTrace .

     string GetPropertyName()
    {
        StackTrace callStackTrace = new StackTrace();
        StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame
        string properyAccessorName = propertyFrame.GetMethod().Name;

        return properyAccessorName.Replace("get_","").Replace("set_","");
    }
 

3voto

stevieg Points 63

FWIW J'ai implémenté un système comme celui-ci:

     [CrmAttribute("firstname")]
    public string FirstName
    {
       get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); }
       set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); }
    }

    // this is in a base class, skipped that bit for clairty
    public T GetPropValue<T>(string propName)
    {
        propName = propName.Replace("get_", "").Replace("set_", "");
        string attributeName = GetCrmAttributeName(propName);
        return GetAttributeValue<T>(attributeName);            
    }

    public void SetPropValue(string propName, object value)
    {
        propName = propName.Replace("get_", "").Replace("set_", "");
        string attributeName = GetCrmAttributeName(propName);
        SetAttributeValue(attributeName, value);
    }

    private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>();
    private string GetCrmAttributeName(string propertyName)
    {
         // keyName for our propertyName to (static) CrmAttributeName cache
         string keyName = this.GetType().Name + propertyName;
         // have we already done this mapping?
         if (!PropToAttributeMap.ContainsKey(keyName))
         {
             Type t = this.GetType();
             PropertyInfo info = t.GetProperty(propertyName);
             if (info == null)
             {
                 throw new Exception("Cannot find a propety called " + propertyName);
             }

             object[] attrs = info.GetCustomAttributes(false);
             foreach (object o in attrs)
             {
                 CrmAttributeAttribute attr = o as CrmAttributeAttribute ;
                 if (attr != null)
                 {
                     // found it. Save the mapping for next time.
                     PropToAttributeMap[keyName] = attr.AttributeName;
                     return attr.AttributeName;
                 }
              }
              throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value");
           }

           // return the existing mapping
           string result = PropToAttributeMap[keyName];
           return result;
        }
 

Il existe également une classe d'attributs personnalisée appelée CrmAttributeAttribute.

Je recommande fortement l'utilisation GetStackFrame () dans le cadre de votre solution, ma version originale de la solution était à l' origine de la beaucoup plus propres:

 return GetPropValue<string>();
 

Mais c'était 600x plus lent que la version ci-dessus.

0voto

Natrium Points 14040

Oui, ça l'est!

 string test = "test string";
Type type = test.GetType();

PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++) 
{
    PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
    string propName = pi.Name;
}
 

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