見出し画像

[.NET] リフレクション スニペット集

よく使いそうなリフレクションのスニペットを集めてみました。
※型を明示するため、var はあえて使用していません(一部除く)。
※安全性と処理速度を考慮し、利用は必要最低限に絞りましょう。

▼インスタンス生成

public/引数なし

Sample sample = Activator.CreateInstance<Sample>();

public/引数あり

object[] args = new object[] { true };
Sample sample = (Sample)Activator.CreateInstance(typeof(Sample), args);

非 public/引数あり

object[] args = new object[] { 1 };
Sample sample = (Sample)Activator.CreateInstance(typeof(Sample), BindingFlags.NonPublic | BindingFlags.Instance, null, args, null);

▼フィールドアクセス

非 public/インスタンスフィールド
※静的フィールドの場合、BindingFlags.Instance → BindingFlags.Static

Sample sample = new Sample();
FieldInfo field = sample.GetType().GetField("privateField", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(sample, true);
bool fieldValue = (bool)field.GetValue(sample);

▼プロパティアクセス

非public/インスタンスプロパティ
※静的フィールドの場合、BindingFlags.Instance → BindingFlags.Static

Sample sample = new Sample();
PropertyInfo property = sample.GetType().GetProperty("PrivateProperty", BindingFlags.NonPublic | BindingFlags.Instance);
property.SetValue(sample, true, null);
bool propertyValue = (bool)property.GetValue(sample, null);

▼メソッド呼び出し

非 public/インスタンスメソッド

Sample sample = new Sample();
MethodInfo method = sample.GetType().GetMethod("PrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
object[] args = new object[] { 1 };
bool returnValue = (bool)method.Invoke(sample, args);

ref 引数

// 引数を false から true に変える ChangeByRefToTrue メソッドを呼び出す。
Sample sample = new Sample();
Type[] paramTypes = new Type[] { typeof(bool).MakeByRefType() };
MethodInfo method = sample.GetType().GetMethod("ChangeByRefToTrue", BindingFlags.NonPublic | BindingFlags.Instance, null, paramTypes, null);
bool inValue = false;
object[] args = new object[] { inValue };
method.Invoke(sample, args);
bool outValue = (bool)args[0];

Assert.IsFalse(inValue);
Assert.IsTrue(outValue);

▼属性情報

SampleAttribute attribute = (SampleAttribute)Attribute.GetCustomAttribute(typeof(Sample), typeof(SampleAttribute));
bool attributeProperty = attribute.Foo;

▼アセンブリ情報

現在実行中のコードを格納しているアセンブリ

Assembly executingAssembly = Assembly.GetExecutingAssembly();

現在実行中のメソッドを呼び出したメソッドのアセンブリ

Assembly callingAssembly = Assembly.GetCallingAssembly();

実行可能ファイルのアセンブリ
※アンマネージアプリケーションから読み込まれている場合、null

Assembly entryAssembly = Assembly.GetEntryAssembly();

実行可能ファイルのパス

string exePath = Application.ExecutablePath;

▼型情報

型判定

Type type = typeof(Sample);
// 列挙型か。
bool isEnum = type.IsEnum;
// 値型か。
bool isValueType = type.IsValueType;
// Nullを許可する値型か。
bool isNullableValueType = (Nullable.GetUnderlyingType(type) != null);

型名

Assert.AreEqual("String", typeof(String).Name);

型名(コンパイル時解決)
※C# 6.0 / VB 2015~ ならリフレクションよりまずこちらを検討

Assert.AreEqual("String", nameof(String));

▼メソッド情報

現在のメソッド名

string currentMethodName = MethodBase.GetCurrentMethod().Name;

呼び出し元のメソッド名
※コンパイラによってインライン展開されていないことが前提です。
※.NET 4.5~ は、CallerMemberNameAttribute を使用して引数から取得できます。

StackFrame frame = new StackFrame(1);
string callerMethodName = frame.GetMethod().Name;

メソッド名(コンパイル時解決)
※C# 6.0 / VB 2015~ ならリフレクションよりまずこちらを検討

Assert.AreEqual("IndexOf", nameof(String.IndexOf));

▼プロパティ情報

現在のプロパティ名

public bool Property
{
   get
   {
       MethodBase accessor = MethodBase.GetCurrentMethod();
       string propertyName = GetProperty(accessor).Name;
       return true;
   }
}

アクセサからプロパティ情報を取得するメソッド

public static PropertyInfo GetProperty(MethodBase accessor)
{
   PropertyInfo[] properties = accessor.DeclaringType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
   foreach (PropertyInfo property in properties)
   {
       MethodInfo[] methods = property.GetAccessors(true);
       foreach (MethodInfo method in methods)
       {
           if (method == accessor)
           {
               return property;
           }
       }
   }
   return null;
}

Lambda 式からプロパティ名を取得するメソッド

public static string GetPropertyName<TObject, TProperty>(Expression<Func<TObject, TProperty>> getter)
{
   var lambda = (LambdaExpression)getter;
   var memberExpression = lambda.Body as MemberExpression;
   
   if (memberExpression == null)
   {
       // TProperty が object の場合、ボックス化によって UnaryExpression となる。
       var body = (UnaryExpression)lambda.Body;
       memberExpression = (MemberExpression)body.Operand;
   }
   
   return memberExpression.Member.Name;
}

// 使用例
string propertyName = GetPropertyName((Sample s) => s.PublicProperty);

プロパティ名(コンパイル時解決)
※C# 6.0 / VB 2015~ ならリフレクションよりまずこちらを検討

Assert.AreEqual("Length", nameof(String.Length));

この記事が気に入ったらサポートをしてみませんか?