特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
一个自定义特性类必须直接或间接继承自System.Attribute特性类。.
为该自定义特性类指定System.AttributeUsage特性,并指定限制参数(枚举System.AttributeTargets和可选的AllowMultiple、Inherited命名参数)。AttributeUsage的命名参数:AllowMultiple表示是否允许多次使用在同一目标上、Inherited表示是否同时应用于派生类型或重载版本。
类名是特性的名称。
构造函数的参数是自定义特性的定位参数(应用该特性时必须放在参数列表的最前面),也可以是无参构造函数(如[Serializable])。
任何公共的读写字段或属性都是可选的命名参数。
如果特性类包含一个属性,则该属性必须为读写属性。
C#中的Reflection(反射)
反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
你可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
优点:
反射提高了程序的灵活性和扩展性。
降低耦合性,提高自适应能力。
它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
缺点:
性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
反射(Reflection)的用途
它允许在运行时查看特性(attribute)信息。
它允许审查集合中的各种类型,以及实例化这些类型。
它允许延迟绑定的方法和属性(property)。
它允许在运行时创建新类型,然后使用这些类型执行一些任务。
案例
/// <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;
}