属性构造和λ [英] Attribute Constructor With Lambda
问题描述
它的是可能做到这一点:
public static void SomeMethod<TFunc>(Expression<TFunc> expr)
{
//LambdaExpression happily excepts any Expession<TFunc>
LambdaExpression lamb = expr;
}
和调用它在其他地方传递一个lambda的参数:
and call it elsewhere passing a lambda for the parameter:
SomeMethod<Func<IQueryable<Person>,Person>>( p=>p.FirstOrDefault());
我反而想传递一个前pression作为参数传递给一个属性构造。
是否可以做下面的?
class ExpandableQueryAttribute: Attribute {
private LambdaExpression someLambda;
//ctor
public ExpandableQueryMethodAttribute(LambdaExpression expression)
{
someLambda = expression
}
}
//usage:
static LambdaExpression exp =
(Expression<Func<IQueryable<Person>, Person>>)
(p => p.FirstOrDefault());
[ExpandableQueryAttribute(exp)] //error here
// "An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type"
我的目标是指定属性的构造方法或lambda(即使我不得不宣布一个完整的命名方法,并以某种方式传递方法的名字,我不会有事到)。
My goal is to specify a method or lambda in the constructor of the attribute(even if I have to declare a full named method and pass the name of the method somehow, that'd be fine to).
-
参数类型可以改变,但该属性的构造可以采取的参数,并在某种程度上可以把它分配给类型LambdaEx pression的领域
Parameter types can change, but it is important that the attribute constructor can take that parameter and in some way be able to assign it to a field of type LambdaExpression
我想在lambda /方法的声明只是在调用构造属性,或内联上面,这样你就不必去,远远看见被传递的东西。
I want the declaration of the lambda/method to be just above the call to the attribute constructor, or inline, so that you don't have to go far to see what is being passed.
因此,这些替代品将被罚款,但没有运气让他们工作:
So these alternatives would be fine, but no luck getting them to work:
public static ... FuncName(...){...}
[ExpandableQueryAttribute(FuncName)]
// ...
或
//lambdas aren't allowed inline for an attribute, as far as I know
[ExpandableQueryAttribute(q => q.FirstOrDefault())]
// ...
现有的解决办法是一个数字ID传递给构造函数(满足的说法必须是一个常量的要求),用于由构造进行查找在EX pressions已经字典加previously。希望能改进/简化这一点,但我有一种感觉它没有得到任何的限制,由于更好的属性构造。
The existing work around is to pass a number ID to the constructor(satisfying the "argument must be a constant" requirement), which is used by the constructor to do a lookup in a dictionary where expressions have been added previously. Was hoping to improve/simplify this, but I have a feeling it doesn't get any better due to limitations on attribute constructors.
推荐答案
这个怎么样:
class ExpandableQueryAttribute : Attribute
{
private LambdaExpression someLambda;
//ctor
public ExpandableQueryAttribute(Type hostingType, string filterMethod)
{
someLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
// could also use a static method
}
}
这应该让你的拉姆达分配给字段,然后在运行时吸吮,虽然在一般我会preFER使用类似PostSharp在编译时做到这一点。
this should let you assign your lambda to a field and then suck it in at runtime, although in general I would prefer to use something like PostSharp to do this at compile time.
简单的使用例子
public class LambdaExpressionAttribute : Attribute
{
public LambdaExpression MyLambda { get; private set; }
//ctor
public LambdaExpressionAttribute(Type hostingType, string filterMethod)
{
MyLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
}
}
public class User
{
public bool IsAdministrator { get; set; }
}
public static class securityExpresions
{
public static readonly LambdaExpression IsAdministrator = (Expression<Predicate<User>>)(x => x.IsAdministrator);
public static readonly LambdaExpression IsValid = (Expression<Predicate<User>>)(x => x != null);
public static void CheckAccess(User user)
{
// only for this POC... never do this in shipping code
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
var filters = method.GetCustomAttributes(typeof(LambdaExpressionAttribute), true).OfType<LambdaExpressionAttribute>();
foreach (var filter in filters)
{
if ((bool)filter.MyLambda.Compile().DynamicInvoke(user) == false)
{
throw new UnauthorizedAccessException("user does not have access to: " + method.Name);
}
}
}
}
public static class TheClass
{
[LambdaExpression(typeof(securityExpresions), "IsValid")]
public static void ReadSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("read something");
}
[LambdaExpression(typeof(securityExpresions), "IsAdministrator")]
public static void WriteSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("wrote something");
}
}
static void Main(string[] args)
{
User u = new User();
try
{
TheClass.ReadSomething(u, new object());
TheClass.WriteSomething(u, new object());
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
这篇关于属性构造和λ的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!