C#中的Attribte(特性)

特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。

  1. 一个自定义特性类必须直接或间接继承自System.Attribute特性类。.

  2. 为该自定义特性类指定System.AttributeUsage特性,并指定限制参数(枚举System.AttributeTargets和可选的AllowMultiple、Inherited命名参数)。AttributeUsage的命名参数:AllowMultiple表示是否允许多次使用在同一目标上、Inherited表示是否同时应用于派生类型或重载版本。

  3. 类名是特性的名称。

  4. 构造函数的参数是自定义特性的定位参数(应用该特性时必须放在参数列表的最前面),也可以是无参构造函数(如[Serializable])。

  5. 任何公共的读写字段或属性都是可选的命名参数。

  6. 如果特性类包含一个属性,则该属性必须为读写属性。

C#中的Reflection(反射)

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
你可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

优点

  1. 反射提高了程序的灵活性和扩展性。

  2. 降低耦合性,提高自适应能力。

  3. 它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

缺点

  1. 性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。

  2. 使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

反射(Reflection)的用途

  1. 它允许在运行时查看特性(attribute)信息。

  2. 它允许审查集合中的各种类型,以及实例化这些类型。

  3. 它允许延迟绑定的方法和属性(property)。

  4. 它允许在运行时创建新类型,然后使用这些类型执行一些任务。

案例

    /// <summary>    /// 表达 该属性 是否为用户输入的,还是从之前的模板带出来的    /// </summary>    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]    public class PropertyIsUserInputAttribute : Attribute    {        public bool IsUserInput;        public PropertyIsUserInputAttribute(bool isUserInput)        {            IsUserInput = isUserInput;        }    }    // 使用    public class TestDataModel    {        [PropertyExcelColumnIndex("B")]        [PropertyIsUserInput(false)]        public string 名称 { get; set; }        [PropertyExcelColumnIndex("C")]        [PropertyIsUserInput(true)]        public string 备注 { get; set; }    }        // 通过反射取特性的信息    public static int GetPropertyExcelColumnIndexValue(this BaseSheetModel obj, string propertyName)    {        var referencedType = obj.GetType();        int mappingColumnIndex = -1;        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(referencedType);        if (properties != null)        {            PropertyDescriptor property = properties[propertyName];            if (property != null)            {                AttributeCollection attributeCollection = property.Attributes;                PropertyExcelColumnIndexAttribute mappingAttribute = (PropertyExcelColumnIndexAttribute)attributeCollection[typeof(PropertyExcelColumnIndexAttribute)];                if (mappingAttribute == null)                {                    return mappingColumnIndex;                }                mappingColumnIndex = ExcelFunction.ToIndex(mappingAttribute.ExcelColumnName);            }        }        if (mappingColumnIndex < 0)        {            throw new Exception($"没有找到{propertyName}的Excel映射位置。");        }        return mappingColumnIndex;    }