zoukankan      html  css  js  c++  java
  • C#进阶之特性(Attribute)

    相信只要是用过.net MVC的开发都用过特性,例如最基础的HttpMethodAttribute特性,用来给接口进行请求方式限定的,等等诸如此类的特性,数不胜数。

    那么什么是特性?

    特性就是一个类,直接或者间接继承自Attribute,特性本身没有任何作用

    特性的使用方法有两种:

            [Range(0,10)]
            [Test]
            ///分开单独使用
            public int Hight { set; get; }
            [Test, Range(0, 10)]
            ///合并使用,通过逗号分隔
            public string Name { set; get; }

    attribute的使用规则,一般通过在特性类上使用AttributeUsage特性来进行设置

    这个特性有三个属性:

    AllowMultiple:是否允许重复使用;

    Inherited:是否可以被继承;

    构造函数有AttributeTargets类型的参数,主要用来设置特性的使用场景(类、接口、属性、字段……)

    特性的使用场景:

    用来做标记,通过判断类、属性……是否有这个特性,来进行一些业务逻辑上的判断,比如:

    具体是通过System.Reflection程序集提供的反射功能来进行特性获取,

    譬如判断一个类型是否具有某个特性,使用的是IsDefined方法,

    获取一个类的所有特性,使用的是GetCustomAttributes方法,获取的是一个object[],可以通过as进行强转为需要判断的类型;

    1、一些预设的特性

    ObsoleteAttribute:可以通过添加这个特性,对类、属性、接口等进行代码过期设置;

    ConditionalAttribute:通过在方法上设置这个特性,可以屏蔽掉对该方法的所有调用(不过支持返回值是void的方法,毕竟只有这样才不会有在调用的时候有上下文);

    经常看到错误日志里面有很详细的信息,具体到了某某文件多少行哪个方法出错等等,其实微软也提供了对应的特性,支持我们自己查看这些内容:

    /// <summary>
            /// 
            /// </summary>
            /// <param name="filePath">调用的文件物理路径</param>
            /// <param name="num">被调用的行</param>
            /// <param name="name">调用的方法</param>
            public void Call2(string str,
                [CallerFilePath] string filePath = "",
                [CallerLineNumber] int num = 0,
                [CallerMemberName] string name = "")
            {
            }

    2、接口的模型绑定属性验证

     可以通过继承ValidationAttribute,并重写IsValid方法即可实现自定义的属性绑定校验。

    /// <summary>
        ///  
        /// </summary>
        [AttributeUsage(AttributeTargets.All,AllowMultiple = true,Inherited = true)]
        public class RangeAttribute : ValidationAttribute
        {
            public RangeAttribute(int minNum, int maxNum)
            {
                MaxNum = maxNum;
                MinNum = minNum;
            }
    
            public int? MaxNum { set; get; }
            public int? MinNum { set; get; }
            public override bool IsValid(object value)
            {
                var result = false;
                if (MaxNum != null)
                    result = (int)value < MaxNum;
                if (MinNum != null)
                    result = result && (int)value > MinNum;
                return result;
            }
        }

    3、可以用来做属性的标记

    举个例子,比如我想要对一个列表进行多个字段的检索,比如这个实体

    /// <summary>
        /// 全局搜索查询demo实体
        /// </summary>
        public class SerachEntity
        {
            /// <summary>
            /// 姓名
            /// </summary>
            [GlobalSerach]
            [Export("姓名")]
            public string Name { set; get; }
            /// <summary>
            /// 中文名
            /// </summary>
            [GlobalSerach]
            [Export("中文名")]
            public string CName { set; get; }
            /// <summary>
            /// 英文名
            /// </summary>
            [GlobalSerach]
            [Export("英文名")]
            public string EName { set; get; }
            /// <summary>
            /// 地址
            /// </summary>
            [GlobalSerach]
            [Export("地址")]
            public string Address { set; get; }
            /// <summary>
            /// IP
            /// </summary>
            [Export("IP地址")]
            public string IP { set; get; }
        }
        /// <summary>
        /// 全局搜索的标记特性
        /// </summary>
        public class GlobalSerachAttribute : Attribute
        { 
            
        }

    我想要对这些属性进行一个综合的查询

    那么不可能来一个需求我就写一个where吧,这样并不符合封装的思想,所以我需要做的就是寻找共同点,进行封装

    public static class BaseSerach 
        {
            private static List<BinaryExpression> exps = new List<BinaryExpression>();
            private static ParameterExpression m_Parameter = null;
            /// <summary>
            /// where全局查找语句
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="iEnumerables"></param>
            /// <param name="str"></param>
            /// <returns></returns>
            public static IEnumerable<T> WhereByGlobalSerach<T>(this IEnumerable<T> iEnumerables, string str)
                where T : class
            {
                m_Parameter = Expression.Parameter(typeof(T), "x");
                var propertys = typeof(T).GetProperties().Where(t => !(t.IsDefined(typeof(SerializableAttribute), true))).ToList();
                propertys.ForEach(t=> {
                    MemberExpression member = Expression.PropertyOrField(m_Parameter, t.Name);
                    Expression exp1 = Expression.NotEqual(member, Expression.Constant(null));//判断是否为null
                    Expression exp2 = Expression.Call(member, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(str));
                    exps.Add(Expression.AndAlso(exp1, exp2));
                });
                return iEnumerables.Where(GetLambda<T>());
    
            }
            /// <summary>
            /// 获取表达式
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <returns></returns>
            private static Func<T, bool> GetLambda<T>()
                where T : class
            {
                Expression whereExpr = null;
                foreach (var expr in exps)
                {
                    if (whereExpr == null)
                        whereExpr = expr;
                    else
                        whereExpr = Expression.Or(whereExpr, expr);
                }
                if (whereExpr == null)
                    return null;
                return Expression.Lambda<Func<T, bool>>(whereExpr, m_Parameter).Compile();
            }
        }

    这里的方法就可以用来进行泛型的普遍属性检索,

    调用起来也很简单

                var beforeList = new List<SerachEntity>() { new SerachEntity() {Name="余成" },new SerachEntity() {Name="余承浩" } };
                var lastList = beforeList.WhereByGlobalSerach("");

    我感觉这就是特性最好用的一点了,用于标记。

  • 相关阅读:
    [WPF 自定义控件]好用的VisualTreeExtensions
    [UWP]从头开始创建并发布一个番茄钟
    [WPF 自定义控件]使用TextBlockHighlightSource强化高亮的功能,以及使用TypeConverter简化调用
    [WPF 自定义控件]排序、筛选以及高亮
    《写给大家看的设计书》,推荐给想了解设计的程序员
    [WPF 自定义控件]使用WindowChrome自定义RibbonWindow
    [书籍]通过《番茄工作法图解》复习番茄工作法
    [WPF 自定义控件]使用WindowChrome的问题
    [WPF 自定义控件]使用WindowChrome自定义Window Style
    时时监听input内容的改变
  • 原文地址:https://www.cnblogs.com/yuchenghao/p/12210708.html
Copyright © 2011-2022 走看看