C# Attribute

C# Attribute

经常碰到使用Attribute的地方,但是基本没有自定义使用过,有时间稍稍学习理解下。

Attribute定义

Attribute本身是个类(Class),一个继承了System.Attribute的类。AttributeTargets枚举类型帮助确定Attribute适用对象。

    [AttributeUsage(AttributeTargets.Property)]
    public class RequiredAttribute : System.Attribute
    {
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class MaxStringLengthAttribute : System.Attribute
    {
        public int MaxLength;        
    }


    [AttributeUsage(AttributeTargets.Property)]
    public class StandardWeightAttribute : System.Attribute
    {
        public int MinWeight;
        public int MaxWeight;

        public StandardWeightAttribute(int minWeight, int maxWeight)
        {
            MinWeight = minWeight;
            MaxWeight = maxWeight;
        }
    }


    [AttributeUsage(AttributeTargets.Class)]
    public class ColorAttribute : System.Attribute
    {
        public FruitColor Color;
    }

Attribute使用

可以在类,属性,方法等上方通过[Attribute(parameter…)]的方式引用Attribute。
有构造方法的可以通过构造方法给属性赋值,没有加入构造方法的public属性可以通过[Attribute(parameter1, parameter2=value,…)]的方式给属性赋值。

    public class QualifiedFruit
    {
        [Required]
        [MaxStringLength(MaxLength = 32)]
        public string Name { get; set; }

        public decimal Price { get; set; }

        public virtual int Weight { get; set; }

        public FruitColor Color { get; set; }
    }

    [Color(Color = FruitColor.YELLOW)]
    public class QualifiedYellowKiWiFruit : QualifiedFruit
    {

        [StandardWeight(100, 120)]
        public override int Weight { get => base.Weight; set => base.Weight = value; }

    }

    [Color(Color = FruitColor.GREEN)]
    public class QualifiedGreenKiWiFruit : QualifiedFruit
    {

        [StandardWeight(120, 150)]
        public override int Weight { get => base.Weight; set => base.Weight = value; }

    }

    public enum FruitColor
    {
        RED,
        GREEN,
        YELLOW
    }

写个验证方法,或者扩展方法来验证Attribute。
Attribute基本通过反射的方式去获取。

    public static class QualifiedFruitExt
    {
        public static bool IsStandard(this QualifiedFruit fruit)
        {
            var fruitType = fruit.GetType();
            var attrs = fruitType.GetCustomAttributes(false);

            // ColorType check
            foreach(var attr in attrs)
            {
                if(attr.GetType().Name == typeof(ColorAttribute).Name)
                {
                    var color = ((ColorAttribute)attr).Color;
                    if(color != fruit.Color)
                    {
                        return false;
                    }
                }
            }

            // Name check
            var propName = fruitType.GetProperty("Name");
            var propNameAttrs = propName.GetCustomAttributes(true);
            foreach(var attr in propNameAttrs)
            {
                if(attr.GetType().Name == typeof(RequiredAttribute).Name)
                {
                    if (string.IsNullOrEmpty(fruit.Name))
                    {
                        return false;
                    }
                }

                if(attr.GetType().Name == typeof(MaxStringLengthAttribute).Name)
                {
                    var maxLength = ((MaxStringLengthAttribute)attr).MaxLength;
                    if(!string.IsNullOrEmpty(fruit.Name) && fruit.Name.Length > maxLength)
                    {
                        return false;
                    }
                }
            }

            // Weight check
            var propWeight = fruitType.GetProperty("Weight");
            var propWeightAttrs = propWeight.GetCustomAttributes(true);
            foreach (var attr in propWeightAttrs)
            {
                if (attr.GetType().Name == typeof(StandardWeightAttribute).Name)
                {
                    var min = ((StandardWeightAttribute)attr).MinWeight;
                    var max = ((StandardWeightAttribute)attr).MaxWeight;
                    if (fruit.Weight > max || fruit.Weight < min)
                    {
                        return false;
                    }
                }
            }

            return true;
        }
    }

做一个简单的验证。

    static void Main(string[] args)
    {
        QualifiedFruit fruit1 = new QualifiedGreenKiWiFruit
        {
            Name = "Super Delicious",
            Price = 1000.00m,
            Weight = 220,
            Color = FruitColor.GREEN
        };
        var isStandard = fruit1.IsStandard();
    }

Attribute使用场景

.Net MVC下面有不少Attribute的使用场景,像DataAnnotationsMVC库下的一些Attribute,还需要进一步学习。

问题

1.为什么使用Attribute?
找了些回答,大体意思是做第三方包的时候去用。这些工具包不关心你的业务逻辑,它们处理一些共通的东西,并且需要在运行时通过反射来做这些事。
不知道自己程序内部有哪些运用Attribute的好的场景。

### C# 中的 Attribute 使用方法与示例 在 C# 中,属性(Attribute)是一种用于向代码添加元数据的机制。通过使用属性,开发者可以为类、方法、属性等代码元素附加额外的信息,这些信息可以在编译时或运行时被访问和处理。以下是关于 C# 属性的详细说明和示例。 #### 1. 基本概念 属性是继承自 `System.Attribute` 的类[^2]。它们通常用于描述代码的行为或特性。例如,可以使用属性来指定方法是否可以并行执行、类的序列化方式等。属性可以通过 `[AttributeName]` 的语法附加到代码元素上。 #### 2. 自定义属性 创建自定义属性需要定义一个继承自 `System.Attribute` 的类。以下是一个简单的自定义属性示例: ```csharp [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class MyCustomAttribute : Attribute { public string Description { get; set; } public int Priority { get; set; } public MyCustomAttribute(string description, int priority) { Description = description; Priority = priority; } } ``` 在这个例子中,`MyCustomAttribute` 是一个自定义属性,它包含两个字段:`Description` 和 `Priority`。通过 `[AttributeUsage]`,可以指定该属性可以应用的目标以及是否允许多次使用。 #### 3. 使用自定义属性 一旦定义了自定义属性,就可以将其应用于类或方法。例如: ```csharp [MyCustom("This is a test class", Priority = 1)] public class TestClass { [MyCustom("This is a test method", Priority = 2)] public void TestMethod() { Console.WriteLine("TestMethod executed."); } } ``` #### 4. 访问属性 要访问附加到代码元素上的属性,可以使用反射(Reflection)。以下是一个读取属性值的示例: ```csharp var type = typeof(TestClass); var customAttributes = type.GetCustomAttributes(typeof(MyCustomAttribute), false); foreach (MyCustomAttribute attr in customAttributes) { Console.WriteLine($"Description: {attr.Description}, Priority: {attr.Priority}"); } var method = typeof(TestClass).GetMethod("TestMethod"); var methodAttributes = method.GetCustomAttributes(typeof(MyCustomAttribute), false); foreach (MyCustomAttribute attr in methodAttributes) { Console.WriteLine($"Description: {attr.Description}, Priority: {attr.Priority}"); } ``` #### 5. 内置属性 C# 提供了许多内置属性,例如 `[Obsolete]`、`[Serializable]` 和 `[Conditional]` 等。以下是一些常用内置属性的示例: - **[Obsolete]**:标记过时的代码。 ```csharp [Obsolete("This method is deprecated, use NewMethod instead.")] public void OldMethod() { // Method implementation } ``` - **[Serializable]**:标记可序列化的类。 ```csharp [Serializable] public class SerializableClass { public string Data { get; set; } } ``` - **[Conditional]**:根据条件编译代码。 ```csharp [Conditional("DEBUG")] public void DebugOnlyMethod() { Console.WriteLine("This method runs only in DEBUG mode."); } ``` #### 6. 设计原则 在设计属性时,应遵循单一职责原则(Single Responsibility Principle),确保每个类和方法只专注于实现单一功能[^3]。如果某些逻辑可以被复用,建议将其提取到工具类(Utility Class)中,以保持代码的清晰性和可维护性。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值