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

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

# インスタンス生成

### public／引数なし
```c#
Sample sample = Activator.CreateInstance<Sample>();
```

### public／引数あり
```c#
object[] args = new object[] { true };
Sample sample = (Sample)Activator.CreateInstance(typeof(Sample), args);
```

### 非 public／引数あり
```c#
object[] args = new object[] { 1 };
Sample sample = (Sample)Activator.CreateInstance(typeof(Sample), BindingFlags.NonPublic | BindingFlags.Instance, null, args, null);
```

# フィールドアクセス

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

```c#
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

```c#
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／インスタンスメソッド
```c#
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 引数
```c#
// 引数を 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);
```
 
# 属性情報
```c#
SampleAttribute attribute = (SampleAttribute)Attribute.GetCustomAttribute(typeof(Sample), typeof(SampleAttribute));
bool attributeProperty = attribute.Foo;
```
 
# アセンブリ情報

### 現在実行中のコードを格納しているアセンブリ
```c#
Assembly executingAssembly = Assembly.GetExecutingAssembly();
```
### 現在実行中のメソッドを呼び出したメソッドのアセンブリ
```c#
Assembly callingAssembly = Assembly.GetCallingAssembly();
```
### 実行可能ファイルのアセンブリ
※アンマネージアプリケーションから読み込まれている場合、null

```c#
Assembly entryAssembly = Assembly.GetEntryAssembly();
```
### 実行可能ファイルのパス
```c#
string exePath = Application.ExecutablePath;
```
 
# 型情報

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

### 型名
```c#
Assert.AreEqual("String", typeof(String).Name);
```
### 型名（コンパイル時解決）
※C# 6.0 / VB 2015～ ならリフレクションよりまずこちらを検討

```c#
Assert.AreEqual("String", nameof(String));
```
 
# メソッド情報

### 現在のメソッド名
```c#
string currentMethodName = MethodBase.GetCurrentMethod().Name;
```

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

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

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

```c#
Assert.AreEqual("IndexOf", nameof(String.IndexOf));
```
 
# プロパティ情報

### 現在のプロパティ名
```c#
public bool Property
{
    get
    {
        MethodBase accessor = MethodBase.GetCurrentMethod();
        string propertyName = GetProperty(accessor).Name;
        return true;
    }
}
```

### アクセサからプロパティ情報を取得するメソッド
```c#
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 式からプロパティ名を取得するメソッド
```c#
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～ ならリフレクションよりまずこちらを検討

```c#
Assert.AreEqual("Length", nameof(String.Length));
```