C#高级

您所在的位置:网站首页 功能特性是什么 C#高级

C#高级

2024-07-09 12:51| 来源: 网络整理| 查看: 265

C#高级–特性详解 零、文章目录 一、特性是什么 1、特性定义

**特性(Attribute)**是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。

特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。

2、特性的语法

特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。

[attribute(positional_parameters, name_parameter = value, ...)] element 3、特性和注释有什么区别

特性很厉害,加了特性之后,就有很厉害的功能 [Obsolete]编译时就有提示,影响了编译器[Obsolete(“请不要使用这个了,请使用什么来代替”, true)]甚至导致编译报错 [Serializable]对象就可以序列化,影响了程序运行

using System; namespace MyAttribute { /// /// 这里是注释,除了让人看懂这里写的是什么,对运行没有任何影响 /// ///[Obsolete("请不要使用这个了,请使用什么来代替")]//对编译都产生了影响,编译出现警告 ///[Obsolete("请不要使用这个了,请使用什么来代替", true)]//对编译都产生了影响,编译报错不通过 [Serializable]//可以序列化和反序列化 public class Student { public int Id { get; set; } public string Name { get; set; } public void Study() { Console.WriteLine($"这里是{this.Name}在学习"); } public string Answer([Custom]string name) { return $"This is {name}"; } } }

特性无处不在:EF–MVC–WCF–WebService–UnitTest–IOC–AOP–SuperSocket

二、特性声明和使用 1、什么是特性

特性其实就是一个类,直接或间接继承自Attribute

#region 程序集 mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 // C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\mscorlib.dll // Decompiled with ICSharpCode.Decompiler 6.1.0.5902 #endregion using System.Reflection; using System.Runtime.InteropServices; namespace System { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)] [ComVisible(true)] public sealed class SerializableAttribute : Attribute { internal static Attribute GetCustomAttribute(RuntimeType type) { if ((type.Attributes & TypeAttributes.Serializable) != TypeAttributes.Serializable) { return null; } return new SerializableAttribute(); } internal static bool IsDefined(RuntimeType type) { return type.IsSerializable; } } } #if false // 反编译日志 缓存中的 9 项 #endif 2、自定义一个特性 using System; namespace MyAttribute { public class CustomAttribute : Attribute { } }

约定俗成用Attribute结尾,标记时就可以省略掉;可以用中括号包裹,然后标记到元素,其实就是调用构造函数;

using System; namespace MyAttribute { [Custom] public class Student { [Custom] public int Id { get; set; } public string Name { get; set; } [Custom] public void Study() { Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习"); } } } 3、AttributeUsage特性

直接在一个元素上添加多个相同的特性,会报错特性重复,需要在特性上面添加特性标记[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]这样就可以给同一个元素添加多个相同的特性了

using System; namespace MyAttribute { [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class CustomAttribute : Attribute { public CustomAttribute() { Console.WriteLine($"{this.GetType().Name} 无参数构造函数执行"); } public CustomAttribute(int id) { Console.WriteLine($"{this.GetType().Name} int参数构造函数执行"); this._Id = id; } public CustomAttribute(string name) { Console.WriteLine($"{this.GetType().Name} string参数构造函数执行"); this._Name = name; } } }

多个相同的特性情况展示

using System; namespace MyAttribute { [Custom] [Custom()] [Custom(0)] public class Student { [Custom] public int Id { get; set; } public string Name { get; set; } [Custom] public void Study() { Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习"); } [Custom(0)] public string Answer([Custom]string name) { return $"This is {name}"; } } }

AttributeUsage特性,影响编译器运行,指定修饰的对象、能否重复修饰、修饰的特性子类是否生效,建议是明确约束用在哪些对象的

[AttributeUsage(AttributeTargets.Method|AttributeTargets.Class|AttributeTargets.Property, AllowMultiple = true)] 4、特性可以指定属性和字段 using System; namespace MyAttribute { [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)] public class CustomAttribute : Attribute { public CustomAttribute() { Console.WriteLine($"{this.GetType().Name} 无参数构造函数执行"); } public CustomAttribute(int id) { Console.WriteLine($"{this.GetType().Name} int参数构造函数执行"); this._Id = id; } public CustomAttribute(string name) { Console.WriteLine($"{this.GetType().Name} string参数构造函数执行"); this._Name = name; } private int _Id = 0; private string _Name = null; public string Remark; public string Description { get; set; } } } using System; namespace MyAttribute { [Custom(Remark = "123")] [Custom(Remark = "123", Description = "456")] [Custom(0, Remark = "123")] [Custom(0, Remark = "123", Description = "456")] public class Student { public int Id { get; set; } public string Name { get; set; } public void Study() { Console.WriteLine($"这里是{this.Name}跟着Eleven老师学习"); } } } 5、特性还可以修饰返回值和参数 using System; namespace MyAttribute { public class Student { [return: Custom] public string Answer([Custom]string name) { return $"This is {name}"; } } } 6、多重修饰既可以中括号隔开,也可以一个中括号里面逗号隔开 using System; namespace MyAttribute { [Custom] [Custom()] [Custom(Remark = "123")] [Custom(Remark = "123", Description = "456")] [Custom(0)] [Custom(0, Remark = "123")] [Custom(0, Remark = "123", Description = "456")] public class Student { [return: Custom, Custom,Custom(), Custom(0, Remark = "123", Description = "456")] public string Answer(string name) { return $"This is {name}"; } } } 三、特性工作原理

自定义的特性,好像毫无意义,那框架提供的特性究竟是怎么产生价值的呢,[Obsolete][AttributeUsage]影响了编译器,这属于系统内置,我们搞不了。

反编译之后,发现特性会在元素内部生成 .custom的东西,是这个东西我们C#访问不到,简直可以理解为,特性没有产生任何变化。但是框架究竟是怎么产生功能的呢?

可以通过反射,从类型,属性,方法都可以获取特性实例,要求先IsDefined检测再获取实例化。程序运行时可以找到特性,需要一个第三方InvokeCenter,在这里去主动检测并且使用特性,才能赋予它功能,只定义特性是没有用的。

using System; namespace MyAttribute { public class InvokeCenter { public static void ManagerStudent(T student) where T : Student { Console.WriteLine($"{student.Id}_{student.Name}"); student.Study(); student.Answer("123"); Type type = student.GetType(); if (type.IsDefined(typeof(CustomAttribute), true)) { //type.GetCustomAttribute() object[] oAttributeArray = type.GetCustomAttributes(typeof(CustomAttribute), true); foreach (CustomAttribute attribute in oAttributeArray) { attribute.Show(); //attribute.Description } foreach (var prop in type.GetProperties()) { if (prop.IsDefined(typeof(CustomAttribute), true)) { object[] oAttributeArrayProp = prop.GetCustomAttributes(typeof(CustomAttribute), true); foreach (CustomAttribute attribute in oAttributeArrayProp) { attribute.Show(); } } } foreach (var method in type.GetMethods()) { if (method.IsDefined(typeof(CustomAttribute), true)) { object[] oAttributeArrayMethod = method.GetCustomAttributes(typeof(CustomAttribute), true); foreach (CustomAttribute attribute in oAttributeArrayMethod) { attribute.Show(); } } } } } } }

特性是在编译时确定的,构造函数/属性/字段,都不能用变量,所以,mvc5-filter是不能注入的,所以在core里面才提供了注入filter的方式

四、特性应用案例 1、特性实现枚举展示描述信息 (1)创建枚举类 namespace MyAttribute.EnumExtend { /// /// 用户状态 /// public enum UserState { /// /// 正常状态 /// [Remark("正常状态")] Normal = 0, /// /// 已冻结 /// [Remark("已冻结")] Frozen = 1, /// /// 已删除 /// [Remark("已删除")] Deleted = 2 } } (2)创建特性类 using System; namespace MyAttribute.EnumExtend { /// /// Remark特性 /// [AttributeUsage(AttributeTargets.Field)] public class RemarkAttribute : Attribute { public string Remark { get; private set; } public RemarkAttribute(string remark) { this.Remark = remark; } } } (3)枚举扩展方法 using System; using System.Reflection; namespace MyAttribute.EnumExtend { public static class AttributeExtend { public static string GetRemark(this Enum value) { Type type = value.GetType(); var field = type.GetField(value.ToString()); if (field.IsDefined(typeof(RemarkAttribute), true)) { RemarkAttribute attribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute), true); return attribute.Remark; } else { return value.ToString(); } } } } (4)枚举调用扩展方法 using MyAttribute.EnumExtend; using MyAttribute.ValidateExtend; using System; namespace MyAttribute { /// /// main方法调用 /// class Program { static void Main(string[] args) { try { #region 特性实现枚举展示描述信息 { UserState userState = UserState.Frozen; string reamrk = userState.GetRemark(); //有了特性,文字其实是直接固化在枚举上面, 如果修改只用改这里 //1 数据展示--不想展示属性名字,而是用一个中文描述 //2 想指定哪个是主键 哪个是自增 //3 别名--数据库里面叫A 程序叫B,怎么映射起来 } #endregion } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read(); } } } 2、特性实现数据验证 (1)基类抽象特性 using System; namespace MyAttribute.ValidateExtend { public abstract class AbstractValidateAttribute : Attribute { public abstract bool Validate(object oValue); } } (2)子类特性实现–数字长度 using System; namespace MyAttribute.ValidateExtend { [AttributeUsage(AttributeTargets.Property)] public class LongAttribute : AbstractValidateAttribute { private long _Min = 0; private long _Max = 0; public LongAttribute(long min, long max) { this._Min = min; this._Max = max; } public override bool Validate(object oValue) { return oValue != null && long.TryParse(oValue.ToString(), out long lValue) && lValue >= this._Min && lValue = this._Min && oValue.ToString().Length


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3