首页 > 编程语言 >C#–特性详解

C#–特性详解

时间:2024-04-05 17:46:16浏览次数:23  
标签:string C# MyAttribute 特性 Custom 详解 using public

一、特性是什么

1、特性定义

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

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

2、特性的语法

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

1
2
[attribute(positional_parameters, name_parameter = value, ...)]
element

3、特性和注释有什么区别

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


using System;

namespace MyAttribute
{
    /// <summary>
    /// 这里是注释,除了让人看懂这里写的是什么,对运行没有任何影响
    /// </summary>
    ///[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}跟着Gerry老师学习");
        }
    }
}

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(10)]    
    public class Student
    {
        [Custom]
        public int Id { get; set; }
        public string Name { get; set; }
        [Custom]
        public void Study()
        {
            Console.WriteLine($"这里是{this.Name}跟着Gerry老师学习");
        }
       
        [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}跟着Gerry老师学习");
        }        
    }
}

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}";
        }
    }
}

四、特性应用案例

1、特性实现枚举展示描述信息

(1)创建枚举类


namespace MyAttribute.EnumExtend
{
    /// <summary>
    /// 用户状态
    /// </summary>
    public enum UserState
    {
        /// <summary>
        /// 正常状态
        /// </summary>
        [Remark("正常状态")]
        Normal = 0,
        /// <summary>
        /// 已冻结
        /// </summary>
        [Remark("已冻结")]
        Frozen = 1,
        /// <summary>
        /// 已删除
        /// </summary>
        [Remark("已删除")]
        Deleted = 2
    }
}

(2)创建特性类


using System;

namespace MyAttribute.EnumExtend
{
    /// <summary>
    /// Remark特性
    /// </summary>
    [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();
            }
        }
    }
}

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 = 4;
        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._Max;
        }
    }
}

(3)子类特性实现–可空


namespace MyAttribute.ValidateExtend
{
    public class RequiredAttribute : AbstractValidateAttribute
    {
        public override bool Validate(object oValue)
        {
            return oValue != null
                && !string.IsNullOrWhiteSpace(oValue.ToString());
        }
    }
}

(4)子类特性实现–字符串长度


using System;

namespace MyAttribute.ValidateExtend
{
    [AttributeUsage(AttributeTargets.Property)]
    public class StringLengthAttribute : AbstractValidateAttribute
    {
        private int _Min = 0;
        private int _Max = 3;
        public StringLengthAttribute(int min, int max)
        {
            this._Min = min;
            this._Max = max;
        }

        public override bool Validate(object oValue)
        {
            return oValue != null
                && oValue.ToString().Length >= this._Min
                && oValue.ToString().Length <= this._Max;
        }
    }
}

(5)泛型扩展方法


using System;

namespace MyAttribute.ValidateExtend
{
    public static class AttributeExtend
    {
        public static bool Validate<T>(this T t)
        {
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            {
                if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
                {
                    object oValue = prop.GetValue(t);
                    foreach (AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true))
                    {
                        if (!attribute.Validate(oValue))
                            return false;
                    }
                }
            }
            return true;
        }
    }
}

(6)常规类字段定义


using System;

namespace MyAttribute.ValidateExtend
{
    public static class AttributeExtend
    {
        public static bool Validate<T>(this T t)
        {
            Type type = t.GetType();
            foreach (var prop in type.GetProperties())
            {
                if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
                {
                    object oValue = prop.GetValue(t);
                    foreach (AbstractValidateAttribute attribute in prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true))
                    {
                        if (!attribute.Validate(oValue))
                            return false;
                    }
                }
            }
            return tue;
        }
    }
}

(7)类调用扩展方法验证字段

using MyAttribute.EnumExtend;
using MyAttribute.ValidateExtend;
using System;

namespace MyAttribute
{
    /// <summary>
    /// main方法调用
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {                
                #region 特性实现数据验证,并且可扩展
                {
                    //通过特性去提供额外行为
                    //数据验证--到处都需要验证
                    StudentVip student = new StudentVip()
                    {
                        Id = 123,
                        Name = "无为",
                        QQ = 729220650,
                        Salary = 1010000
                    };                    

                    if (student.Validate())
                    {
                        Console.WriteLine("特性校验成功");
                    }
                    //1 可以校验多个属性
                    //2 支持多重校验
                    //3 支持规则的随意扩展
                }
                #endregion
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.Read();
        }
    }
}

标签:string,C#,MyAttribute,特性,Custom,详解,using,public
From: https://www.cnblogs.com/lvbjj/p/18115972

相关文章

  • AT-abc347(C,D)
    AtCoderBeginnerContest347C-IdealHolidays这场做得最头疼的题分析容易想到先用$(d_i+a+b-1)%(a+b)+1$把$d_i$映射到$[1,a+b]$的区间再排序,但由于未知星期一是哪天,我们也无法确定映射后的$d_i$是星期几关于这个映射可以自己推一下我们取a+b=7看几个例子对于32......
  • C#-反射详解
    一、反射是什么1、C#编译运行过程高级语言->编译->dll/exe文件->CLR/JIT->机器码2、原理解析metadata:元数据数据清单,记录了dll中包含了哪些东西,是一个描述。IL:中间语言,编译把高级语言编译后得到的C#中最真实的语言状态,面向对象语言。反射:来自于System.Reflection,是一个帮助类......
  • CF1037H Security
    \(CF1037H\\Security\)题意给定一个母串\(s\)和\(T\)次询问,每次询问\(S[l\dotsr]\)中字典序严格大于\(t\)的最小串,没有则输出\(-1\)\[|s|\leq10^5\,\\sum|t|\leq2\times10^5\]思路分析不会,贺了首先,因为这个题的标签里有SAM,所以我们要用SAM壹首先我们......
  • WPF实现树形下拉列表框(TreeComboBox)
    前言树形下拉菜单是许多WPF应用程序中常见的用户界面元素,它能够以分层的方式展示数据,提供更好的用户体验。本文将深入探讨如何基于WPF创建一个可定制的树形下拉菜单控件,涵盖从原理到实际实现的关键步骤。一、需求分析    树形下拉菜单控件的核心是将ComboBox与TreeVi......
  • 在不受支持的 Mac 上安装 macOS Sonoma (OpenCore Legacy Patcher v1.4.3)
    在不受支持的Mac上安装macOSSonoma(OpenCoreLegacyPatcherv1.4.3)InstallmacOSonunsupportedMacs请访问原文链接:在不受支持的Mac上安装macOS(索引页面),查看最新版。原创作品,转载请保留出处。作者主页:sysin.org随着OpenCoreLegacyPatcherv1.4.3的发布,此......
  • Adobe After Effects 2024 v24.3 (macOS, Windows) - 后期特效
    AdobeAfterEffects2024v24.3(macOS,Windows)-后期特效Acrobat、AfterEffects、Animate、Audition、Bridge、CharacterAnimator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、LightroomClassic、MediaEncoder、Photoshop、PremierePro、AdobeXD请访......
  • 特性与反射
    性与反射特性特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([])来描述的。特性(Attribute)用于添加元数据,如编译器指......
  • Adobe InCopy 2024 v19.3 (macOS, Windows) - 编写和副本编辑软件
    AdobeInCopy2024v19.3(macOS,Windows)-编写和副本编辑软件Acrobat、AfterEffects、Animate、Audition、Bridge、CharacterAnimator、Dimension、Dreamweaver、Illustrator、InCopy、InDesign、LightroomClassic、MediaEncoder、Photoshop、PremierePro、AdobeXD......
  • 【Java】轻量Excel读写框架学习
     参考黑马教程:https://www.bilibili.com/video/BV1eA41157va?p=5写着写着发现有更好的Demo案例:https://cloud.tencent.com/developer/article/1966065所需依赖:<dependency><groupId>org.apache.tika</groupId><artifactId>tika-core</artifa......
  • 07 | Swoole 源码分析之 Channel 通道模块
    原文首发链接:Swoole源码分析之Channel通道模块大家好,我是码农先森。引言通道,用于协程间通讯,支持多生产者协程和多消费者协程。底层自动实现了协程的切换和调度。通道与PHP的Array类似,仅占用内存,没有其他额外的资源申请,所有操作均为内存操作,无IO消耗。底层使用......