我想编写一个扩展方法来测试是否在方法调用中应用了一个属性,并且我想将该方法指定为lambda表达式。目前,我有以下(工作)方法,但我真的不喜欢这段代码的样子:
// 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();
正如你所看到的,我必须两次指定委托类型,而且它看起来都不漂亮......我想要更像
// Usage (if I had my way...)
var mut = (c, m, s) => c.LogIn(m, s);
mut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();
但我意识到可能会有点太多了。
有什么方法可以重构我当前代码中的类型参数吗?
我首先在那里有TDelegate
类型参数的原因是我想使用它而不管方法签名和返回类型,并且取决于输入参数的数量以及是否有问题的方法是void
或函数,TDelegate
需要改变。我不想为我测试的方法的每个输入参数数量设置一个不同的实现...
更新
正如Jay在评论中指出的那样,我显然不需要在TDelegate
的调用中指定HasAttribute<>
类型参数。代码现在看起来像这样:
Expression<Func<AccountController, LogInModel, string, ActionResult>> mut = (c, m, s) => c.LogIn(m, s);
mut.HasAttribute<ExportModelStateAttribute>().ShouldBeTrue();
它好多了,但我仍然认为第一行非常混乱。可能会更好吗?
答案 0 :(得分: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();
更新:以显示更新问题的示例。我认为它不会变得更加简化。
答案 1 :(得分:1)
LambdaExpression
代替通用格式Expression<>
吗? (如果是这样,那么TDelegate param可以消失)如果没有,这样可以吗:
// 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);
}
}