属性构造和λ [英] Attribute Constructor With Lambda

查看:103
本文介绍了属性构造和λ的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

它的可能做到这一点:

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).


  1. 参数类型可以改变,但该属性的构造可以采取的参数,并在某种程度上可以把它分配给类型LambdaEx pression的领域

  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆