3

これは、Oliver Hanappiがスタックオーバーフローに投稿した静的リフレクション コードです。

private static string GetMemberName(Expression expression)
    {
        switch (expression.NodeType)
        {
            case ExpressionType.MemberAccess:
                var memberExpression = (MemberExpression)expression;
                var supername = GetMemberName(memberExpression.Expression);

                if (String.IsNullOrEmpty(supername))
                    return memberExpression.Member.Name;

                return String.Concat(supername, '.', memberExpression.Member.Name);

            case ExpressionType.Call:
                var callExpression = (MethodCallExpression)expression;
                return callExpression.Method.Name;

            case ExpressionType.Convert:
                var unaryExpression = (UnaryExpression)expression;
                return GetMemberName(unaryExpression.Operand);

            case ExpressionType.Parameter:
                return String.Empty;

            default:
                throw new ArgumentException("The expression is not a member access or method call expression");
        }
    }

私はパブリックラッパーメソッドを持っています:

public static string Name<T>(Expression<Action<T>> expression)
    {
        return GetMemberName(expression.Body);
    }
public static string Name<T>(Expression<Func<T, object>> expression)
    {
        return GetMemberName(expression.Body);
    }

次に、独自のメソッドのショートカットを追加しました

        public static string ClassMemberName<T>(this T sourceType,Expression<Func<T,object>> expression)
    {
        return GetMemberName(expression.Body);
    }
    public static string TMemberName<T>(this IEnumerable<T> sourceList, Expression<Func<T,object>> expression)
    {
        return GetMemberName(expression.Body);
    }

GetMemberName(Expression expression)スイッチのさまざまな分岐を必要とする、または利用するコードの例は何ですか? このコードは、強く型付けされたものを作ることができますか?

4

2 に答える 2

3

マジック ナンバー (「マジック ストリング」と呼ばれることがある一般的な用語) を渡す必要がある多くの場合、代わりに式を使用してタイプ セーフを提供できます。

一般的な例は、INotifyPropertyChangedインターフェースの実装です。

通常、プロパティ セッターには次のような呼び出しが含まれます。

string _name
public string name
{
    get { return _name; }
    set
    {
        if(value.Equals(_name)) return;
        _name = value;
        OnPropertyChanged("name");
    }
}

ここでは、文字列「name」を渡して、変更されたプロパティを識別しています。これは、チーム リーダーが「すべてのパブリック プロパティを大文字で開始し、接頭辞としてクラス名を付ける」と言うと厄介になります。ここで、プロパティを に変更しましたが、 に変更したPersonNameことを覚えている可能性はどれくらいですか? 特にコードを最初に書いていない場合は高くありません。それでも、プロジェクトはコンパイルされ、デバッグに 20 分かかります。"name""PersonName"

代わりに、次の式を使用します。

string _name
public string name
{
    get { return _name; }
    set
    {
        if(value.Equals(_name)) return;
        _name = value;
        OnPropertyChanged(x => x.name);
    }
}

...そして、OnPropertyChanged実装は投稿したコードを使用して、式本体からプロパティの名前を取得します。

プロパティをPersonNameに変更すると、式も read に変更するまでコードはコンパイルされませんx => x.PersonName。これがあなたのタイプセーフです。

式には任意のタイプのノードが含まれている可能性があるため、コードは明らかにスイッチを使用しています。プロパティにアクセスする必要はありませんMemberExpression。メソッド呼び出し、メソッドのパラメーターなどを参照できます。

を実装するだけの場合は、これだけで十分というわけではありませんINotifyPropertyChangedが、パラメーターなどの検証にも使用している可能性があります。スイッチは、任意のメンバー アクセス式のベースをカバーするだけであり、それ以外のものを指定するとスローします。

于 2010-04-07T21:52:54.187 に答える
2
  • MemberAccess:foo => foo.SomeFieldまたはfoo => foo.SomeProperty
  • Call:foo => foo.SomeMethod(...)
  • Parameter:foo => foo
  • Convert: foo => (int)foo.Something(おそらく暗黙的)
于 2010-04-07T21:37:12.017 に答える