3

メソッド呼び出しで属性が適用されているかどうかをテストする拡張メソッドを作成し、そのメソッドをラムダ式として指定したいと考えています。現在、私は次の(機能する)アプローチを持っていますが、このコードの見た目が本当に好きではありません:

// Signature of my extension method:
public static bool HasAttribute<TAttribute, TDelegate>(this Expression<TDelegate> method)

// Usage (current code)
Expression<Func<AccountController, LogInModel, string, ActionResult>> mut = (c, m, s) => c.LogIn(m, s);
mut.HasAttribute<ExportModelStateAttribute, Func<AccountController, LogInModel, string, ActionResult>>().ShouldBeTrue();

ご覧のとおり、デリゲートの型を 2 回指定する必要がありますが、どちらも見栄えがよくありません...

// Usage (if I had my way...)
var mut = (c, m, s) => c.LogIn(m, s);
mut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();

しかし、それは少し要求が多すぎるかもしれないことに気づきました。

現在のコードから型引数をリファクタリングする方法はありますか?

そもそも型引数がある理由はTDelegate、メソッドのシグネチャと戻り値の型に関係なくこれを使用したいからであり、入力引数の数と、問題のメソッドが avoidか関数かTDelegateによって、変化。テストするメソッドへの入力引数の数ごとに異なる実装をしたくありません...

更新:
Jay がコメントで指摘しているTDelegateように、 の呼び出しで型引数を指定する必要はないようHasAttribute<>です。コードは次のようになります。

Expression<Func<AccountController, LogInModel, string, ActionResult>> mut = (c, m, s) => c.LogIn(m, s);
mut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();

ずっと良くなりましたが、それでも最初の行はかなり厄介だと思います。それはさらに良いでしょうか?

4

2 に答える 2

1

あなたができることの1つは、長い醜いものを次のように置き換えることFunc<AccountController, LogInModel, string, ActionResult>です

public delegate ActionResult myDelegate(AccountController accountController, LogInModel logInModel, string varString);

Expression<myDelegate> mut = (c, m, s) => c.LogIn(m, s);
mut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();

更新:更新された質問の例を示します。私はそれがはるかに単純化されることができるとは思わない。

于 2010-06-22T20:26:09.340 に答える
1
  1. LambdaExpression一般的なフォームの代わりに使用できますExpression<>か? (そうであれば、TDelegate パラメーターはなくなる可能性があります)
  2. そうでない場合、これで問題ありません:

    // Signature of my extension method:
    public static bool HasAttribute<TDelagate>(this Expression<TDelagate> method, 
                                               Type attributeType)
    

問題は、明示的に指定したいタイプと指定したくないタイプがあることです (これは C# では不可能です)。

これらのいずれかを実行できるかどうかに関係なく、式の宣言に完全なデリゲート型を指定する必要があります (少なくとも C# 3 では、C# 4 については合法かどうかわかりません。存在するかどうかはわかりません)。これを回避する方法であるかどうか)。

HasAttribute が私が思うように機能する場合、#1 を実行できると思います。

public static bool HasAttribute<TAttribute>(this LambdaExpression method) {
    if (method.Body.NodeType == ExpressionType.Call) {
        MethodCallExpression call = (MethodCallExpression)method.Body;
        return call.Method.GetCustomAttributes(typeof(TAttribute), true).Any();
    }
    return false;
}

編集:

次のような関数を使用して最初の行を簡素化できると思います。

public static LambdaExpression GetMut<T>(Expression<Func<T>> f) { return f; }
public static LambdaExpression GetMut<T>(Expression<Action<T>> f) { return f; }

使用法を作る:

var l = new LogInModel(); // these variables can be inlined or declared 
var s = "";               // it makes no difference
var mut = Expressions.GetMut<AccountController>(c => c.LogIn(l,s));
mut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();

これをいじるために使用されるコンソールアプリの完全なコード:

class Program {
    static void Main(string[] args) {
        var mut = Expressions.GetMut<AccountController>(c => c.LogIn(new LogInModel(), ""));
        mut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();

        var failmut = Expressions.GetMut<AccountController>(c => c.LogInFails());
        failmut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();

        Console.ReadKey();
    }
}

public class ExportModelStateAttribute : Attribute { }

public class ActionResult { }

public class LogInModel { }

public class AccountController {
    [ExportModelState]
    public ActionResult LogIn(LogInModel model, string s) {
        return new ActionResult();
    }

    public void LogInFails() {}
}

public static class Expressions {
    // only need this to find the method given the class T
    public static LambdaExpression GetMut<T>(Expression<Action<T>> func) { return func; }
    // Signature of my extension method:
    public static bool HasAttribute<TAttribute>(this LambdaExpression method) {
        if (method.Body.NodeType == ExpressionType.Call) {
            MethodCallExpression call = (MethodCallExpression)method.Body;
            return call.Method.GetCustomAttributes(typeof(TAttribute), true).Any();
        }
        return false;
    }

    public static void ShouldBeTrue(this bool obj) {
        Console.WriteLine(obj);
    }
}
于 2010-06-22T21:29:35.843 に答える