Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有Lambda的属性构造函数_C#_Lambda_Custom Attributes - Fatal编程技术网

C# 具有Lambda的属性构造函数

C# 具有Lambda的属性构造函数,c#,lambda,custom-attributes,C#,Lambda,Custom Attributes,可以执行以下操作: public static void SomeMethod<TFunc>(Expression<TFunc> expr) { //LambdaExpression happily excepts any Expession<TFunc> LambdaExpression lamb = expr; } 或 现有的解决方法是将数字ID传递给构造函数(满足“参数必须是常量”的要求),构造函数使用该ID在先前添加了表达式的字典中进

可以执行以下操作:

public static void SomeMethod<TFunc>(Expression<TFunc> expr)
{
    //LambdaExpression happily excepts any Expession<TFunc>
    LambdaExpression lamb = expr;
}


现有的解决方法是将数字ID传递给构造函数(满足“参数必须是常量”的要求),构造函数使用该ID在先前添加了表达式的字典中进行查找。我希望能够改进/简化这一点,但我感觉由于属性构造函数的限制,它并没有变得更好。

这是不可能的,因为可以传递到属性中的内容需要符合CLR的二进制DLL格式,并且无法对任意对象初始化进行编码。例如,对于相同的情况,不能传递可为null的值。限制非常严格。

这个怎么样:

    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
        }
    }
这应该允许您将lambda分配给一个字段,然后在运行时将其吸进,尽管通常我更喜欢在编译时使用PostSharp之类的工具来完成这项工作

简单用法示例

    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);
        }
    }
公共类LambdaExpressionAttribute:属性 { 公共LambdaExpression MyLambda{get;private set;} //执行器 公共LambdaExpressionAttribute(类型hostingType,字符串筛选器方法) { MyLambda=(LambdaExpression)hostingType.GetField(filterMethod.GetValue(null); } } 公共类用户 { 公共布尔IsAdministrator{get;set;} } 公共静态类securityExpresions { 公共静态只读LambdaExpression IsAdministrator=(表达式)(x=>x.IsAdministrator); 公共静态只读LambdaExpression IsValid=(表达式)(x=>x!=null); 公共静态无效检查访问(用户) { //仅适用于此POC…请勿在装运代码中执行此操作 System.Diagnostics.StackTrace StackTrace=新的System.Diagnostics.StackTrace(); var method=stackTrace.GetFrame(1.GetMethod(); var filters=method.GetCustomAttributes(typeof(LambdaExpressionAttribute),true); foreach(过滤器中的var过滤器) { if((bool)filter.MyLambda.Compile().DynamicInvoke(用户)==false) { 抛出新的UnauthorizedAccessException(“用户无权访问:“+method.Name”); } } } } 公共静态类 { [LambdaExpression(typeof(securityExpresions),“IsValid”)] 公共静态void ReadSomething(用户、对象) { securityExpresions.CheckAccess(用户); Console.WriteLine(“读东西”); } [LambdaExpression(typeof(securityexpressions),“IsAdministrator”)] 公共静态无效写入方法(用户、对象和内容) { securityExpresions.CheckAccess(用户); Console.WriteLine(“写了什么”); } } 静态void Main(字符串[]参数) { 用户u=新用户(); 尝试 { ReadSomething(u,newobject()); writeMething类(u,newobject()); } 捕获(例外e) { 控制台写入线(e); } } 使用动态linq:


您可以使属性的构造函数采用一个字符串,该字符串的计算结果为表达式。

虽然您不能为属性使用复杂的构造函数,但在某些情况下,我们需要为该属性创建一个公共属性,并在运行时更新它

self指向类的对象,该对象的属性中包含一些属性。LocalDisplayNameAttribute是一个自定义属性

以下代码将在运行时设置自定义属性类的ResourceKey属性。然后,您可以覆盖DisplayName以输出您想要的任何文本

        static public void UpdateAttributes(object self)
    {
        foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(self))
        {
            LocalDisplayNameAttribute attr =
                prop.Attributes[typeof(LocalDisplayNameAttribute)] 
                    as LocalDisplayNameAttribute;

            if (attr == null)
            {
                continue;
            }

            attr.ResourceKey = prop.Name;
        }
    }

跟随你的感觉。。。属性参数的限制是相当清楚的。这个问题也在这个链接中被问到。答案是目前还不可能@Jamey Yep,这是我列出的最后一个选择,我知道这是一个限制。我希望通过将表达式声明为变量来解决这个问题,但后来“必须是常量”的要求让我明白了。不过,这里的解决方法很有趣,我将尝试它的一个变体。@chrismcall的可能副本添加了一个简单的示例OK我现在明白了,在其他地方声明lambda并通过其名称引用它。。。聪明!
//lambdas aren't allowed inline for an attribute, as far as I know
[ExpandableQueryAttribute(q => q.FirstOrDefault())]   
// ...
    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
        }
    }
    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);
        }
    }
        static public void UpdateAttributes(object self)
    {
        foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(self))
        {
            LocalDisplayNameAttribute attr =
                prop.Attributes[typeof(LocalDisplayNameAttribute)] 
                    as LocalDisplayNameAttribute;

            if (attr == null)
            {
                continue;
            }

            attr.ResourceKey = prop.Name;
        }
    }