FieldInfoが自動実装されたフィールドのものか判定する【C#】
概要
プロパティの実装を省略する自動実装プロパティ(Auto-Implemented Properties)を使うと自動的に見えないフィールドが追加されます。このフィールドはBackingFieldと呼ばれます。BackingFieldは普通にアクセスすることはできませんが、Reflectionを使って全てのFieldInfoを取得するとその中にBackingFieldのFieldInfoが含まれます。BackingFieldのFieldInfoを除外するために区別する方法を調べてみました。
public class Hoge { // 自動実装プロパティを使わない場合 private int m_A; public int a { get { return m_A; } set { m_A = value; } } // 自動実装プロパティを使う場合("<b>k__BackingField"というフィールドが追加される) public int b { get; set; } }
判別方法
自動実装されたフィールドかどうかは以下のようにAttributeをチェックすることで判定できます。
public static bool IsBackingField(FieldInfo field) { return field.IsDefined(typeof(CompilerGeneratedAttribute), false); }
ただし、自動実装プロパティ以外にもフィールドが自動実装されるパターンがあるため、自動実装プロパティによって追加されたフィールドであるかどうかの判定には使えません。
自動実装プロパティと同じように、実装を省略したeventを定義すると自動的にフィールドが追加されます。
public class Hoge { // 自動でフィールドが追加されないevent public event System.Action action0{ add { } remove { } } // 自動でフィールドが追加されるevent("action1"というフィールドが追加される) public event System.Action action1; }
これらはフィールドの名前で区別することができます。
/// <summary> /// 自動実装プロパティによって追加されたフィールドかどうかを判定する /// </summary> public static bool IsPropertyBackingField(FieldInfo field) { return IsBackingField(field) && field.Name[0] == '<'; } /// <summary> /// 自動が省略されたeventによって追加されたフィールドかどうかを判定する /// </summary> public static bool IsEventBackingField(FieldInfo field) { return IsBackingField(field) && field.Name[0] != '<'; }
サンプル
private class Hoge { // 自動でフィールドが追加されないevent public event System.Action action0{ add { } remove { } } // 自動でフィールドが追加されるevent public event System.Action action1; // 自動実装プロパティを使わない場合 private int m_A; public int a { get { return m_A; } set { m_A = value; } } // 自動実装プロパティを使う場合 public int b { get; set; } } public void IsBackingField() { var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; foreach(var field in typeof(Hoge).GetFields(flags)) { UnityEngine.Debug.LogFormat( "{0}: {1}, {2}, {3}", field.Name, IsBackingField(field), IsPropertyBackingField(field), IsEventBackingField(field) ); } }
実行結果
(フィールド名: 自動実装されたものか, プロパティによるものか, イベントによるものか)
action1: True, False, True m_A: False, False, False <b>k__BackingField: True, True, False
環境
- Unity 2019.1.9f1
- VisualStudio 2019