web-dev-qa-db-ja.com

リフレクションを介して現在のプロパティ名を取得する方法は?

リフレクションメカニズムを使用してプロパティ名を取得したいのですが。出来ますか?

更新:私はこのようなコードを持っています:

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

そして、私はこのようなより多くのプロパティが必要なので、次のようなことをしたいと思います:

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

プロパティは実際には単なるメソッドなので、これを実行して、返されたget_をクリーンアップできます。

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

パフォーマンスをプロファイルすると、MethodBase.GetCurrentMethod()がStackFrameよりもはるかに高速であることがわかります。 .NET 1.1では、リリースモードのStackFrameにも問題があります(メモリから3倍高速だったと思います)。

とは言っても、StackFrameの速度低下に関する興味深い議論は ここにあります の場合もありますが、パフォーマンスの問題がそれほど大きな問題を引き起こすことはないと確信しています。

パフォーマンスが心配な場合は、別のオプションとして、プロパティを作成し、プロパティ名に対応する文字列を作成するVisual Studio Intellisenseコードスニペットを作成することもできます。

52
RichardOD

私が理解できない場合を除いて、あなたが提示した少しわかりにくい例。 C#6.0以降では、nameof演算子を使用できます。

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

とにかくゲッター/セッターを処理するメソッドがある場合は、C#4.5 CallerMemberName属性を使用できます。この場合、名前を繰り返す必要はありません。

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;
}  
8
Mike Fuchs

プロパティアクセサーで使用しているプロパティをすでに知っているはずなので、必要なコンテキストについて詳しく知りたいのですが。ただし、必要な場合は、おそらく MethodBase.GetCurrentMethod() 。Nameを使用して、get_/set_の後ろを削除できます。

更新

変更に基づいて、リフレクションではなく継承を使用する必要があると思います。辞書にどのようなデータがあるのか​​はわかりませんが、ローカル変数に型を保持せずに、セダン、ロードスター、バギー、ステーションワゴンなど、実際にはさまざまな車のクラスが必要だと思います。次に、そのタイプのCarに適切な処理を行うメソッドの実装があります。あなたが持っている車の種類を見つけて何かをする代わりに、適切なメソッドを呼び出すだけで、Carオブジェクトはそれがどのタイプであるかに基づいて正しいことを行います。

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

代わりにMethodBase.GetCurrentMethod()を使用してください!

リフレクションは、コンパイル時に実行できない型を処理するために使用されます。現在のプロパティアクセサーの名前の取得はコンパイル時に決定できるため、おそらくリフレクションを使用しないでください。

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

FWIW私はこのようなシステムを実装しました:

    [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;
        }

CrmAttributeAttributeと呼ばれるカスタム属性クラスもあります。

ソリューションの一部としてGetStackFrame()を使用するagainstを強くお勧めします。ソリューションの元のバージョンは、もともとはるかにきれいでした。

return GetPropValue<string>();

ただし、上記のバージョンより600倍遅くなりました。

3
stevieg

はい、そうです!

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

System.Diagnostics.StackTraceを使用して、コールスタックを反映してみてください。プロパティは、呼び出しスタックのどこかにある必要があります(プロパティのコードから直接呼び出す場合は、おそらく一番上にあります)。

0
BlueMonkMN

方法#1

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

方法#2

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

方法#3

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;
}
_

_Props.CurrPropName_または_Props.CurrMethodName_を呼び出すだけです


方法#4

.NET 4.5以降のソリューション:

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

usgae:Props.GetCallerName();

0
Andrew