web-dev-qa-db-fra.com

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

Je voudrais obtenir le nom de la propriété quand je suis dedans 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, j'aimerais faire quelque chose comme ceci:

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

Comme les propriétés ne sont que des méthodes, vous pouvez le faire et 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 définissez les performances, vous devriez trouver MethodBase.GetCurrentMethod () est plus rapide que StackFrame. Dans .NET 1.1, vous aurez également des problèmes avec StackFrame en mode de publication (de mémoire, je pense avoir trouvé que c'était 3 fois plus rapide).

Cela dit, je suis sûr que le problème de performances ne posera pas trop de problèmes, même si une discussion intéressante sur la lenteur de StackFrame peut être trouvée ici .

Je suppose qu'une autre option, si vous aviez le souci des performances, serait de créer un extrait de code Visual Studio Intellisense qui crée la propriété pour vous et crée également une chaîne correspondant au nom de la propriété.

50
RichardOD

J'aimerais en savoir plus sur le contexte dans lequel vous en avez besoin, car il me semble que vous devriez déjà savoir quelle propriété vous utilisez dans l'accesseur de propriété. Si vous devez, cependant, vous pourriez probablement utiliser MethodBase.GetCurrentMethod () . Name et supprimer tout ce qui suit le get_/set_.

Mise à jour :

Sur la base de vos modifications, je dirais que vous devriez utiliser l'héritage plutôt que la réflexion. Je ne sais pas quelles sont les données de votre dictionnaire, mais il me semble que vous voulez vraiment avoir différentes classes de voitures, telles que Sedan, Roadster, Buggy, StationWagon, sans conserver le type dans une variable locale. Ensuite, vous aurez des implémentations de méthodes qui font ce qu'il convient pour ce type de voiture. Au lieu de rechercher votre type de voiture, puis de faire quelque chose, vous appelez simplement la méthode appropriée et l'objet Car fait ce qu'il convient en fonction de son type.

 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...
       }
 }
6
tvanfosson

Utilisez MethodBase.GetCurrentMethod () à la place!

Reflection est utilisé pour travailler avec des types qui ne peuvent pas être réalisés lors de la compilation. Obtenir le nom de l’accesseur de propriété dans lequel vous vous trouvez peut être décidé à la compilation, vous ne devriez donc probablement pas utiliser la réflexion pour cela.

Vous obtenez d'utiliser le nom de la méthode d'accès de la pile d'appels à l'aide de System.Diagnostics.StackTrace cependant.

    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_","");
    }
5
weiqure

Exemple légèrement déroutant que vous avez présenté, à moins que je ne l'obtienne pas. À partir de C # 6.0, vous pouvez utiliser l'opérateur nameof.

public CarType MyProperty
{
    get { return (CarType)this[nameof(MyProperty)]};
    set { this[nameof(MyProperty)] = value]};
}

Si vous avez quand même une méthode qui gère votre getter/setter, vous pouvez utiliser l'attribut CallerMemberName de C # 4.5. Dans ce cas, vous n'avez même pas besoin de répéter le nom.

public CarType MyProperty
{
    get { return Get<CarType>(); }
    set { Set(value); }
}

public T Get<T>([CallerMemberName]string name = null)
{
    return (T)this[name];
}   

public void Set<T>(T value, [CallerMemberName]string name = null)
{
    this[name] = value;
}  
5
Mike Fuchs

FWIW j'ai mis en place 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és appelée CrmAttributeAttribute.

Je recommande fortement contre en utilisant GetStackFrame () dans le cadre de votre solution, ma version originale de la solution était à l’origine beaucoup plus ordonnée:

return GetPropValue<string>();

Mais il était 600 fois plus lent que la version ci-dessus.

3
stevieg

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;
}
0
Natrium

Essayez d’utiliser System.Diagnostics.StackTrace pour réfléchir sur la pile d’appels. La propriété doit figurer quelque part dans la pile d'appels (probablement en haut si vous l'appelez directement à partir du code de la propriété).

0
BlueMonkMN

Voie n ° 1

var a = nameof(SampleMethod);    //a == SampleMethod
var b = nameof(SampleVariable);  //b == SampleVariable
var c = nameof(SampleProperty);  //c == SampleProperty

Voie n ° 2

MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property

Voie n ° 3

de StackTrace:

public static class Props
{
    public static string CurrPropName => 
         (new StackTrace()).GetFrame(1).GetMethod().Name.Replace("set_", "").Replace("get_", "");

    public static string CurrMethodName => 
        (new StackTrace()).GetFrame(1).GetMethod().Name;
}

il vous suffit d'appeler Props.CurrPropName ou Props.CurrMethodName


Voie n ° 4

Solution pour .NET 4.5+:

public static class Props
{
    public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
    {
         return propertyName;
    }
}

usgae: Props.GetCallerName();

0
Andrew