C#11特性:泛型属性

转自:一个大西瓜

链接:easy-dotnet.com/pages/438903/

    在 C#11 中,开发人员可以声明一种基类为 System.Attribute 的泛型类。这种特性提供了一种更方便的语法,用于需要一个 System.Type 参数的属性。之前,您需要创建一个以 Type 作为构造函数参数的属性:

// Before C# 11:
public class TypeAttribute : Attribute
{
   public TypeAttribute(Type t) => ParamType = t;


   public Type ParamType { get; }
}

然后使用 typeof 运算符应用属性:

[TypeAttribute(typeof(string))]
public string Method() => default;

使用这个新特性,您可以创建一个泛型属性:

// C# 11 feature:
public class GenericAttribute<T> : Attribute { }

然后,指定要使用属性的类型参数:

[GenericAttribute<string>()]
public string Method() => default;

应用属性时,必须提供所有类型参数。换句话说,泛型类型必须完全构造。在上面的示例中,空括号 () 可以省略,因为属性没有任何参数。

public class GenericType<T>
{
   [GenericAttribute<T>()] // Not allowed! generic attributes must be fully constructed types.
   public string Method() => default;
}

类型参数必须满足 typeof 运算符的相同限制。不允许使用需要元数据注释的类型。例如,以下类型不能作为类型参数:

  • dynamic

  • string?(或任何可空引用类型)

  • (int X, int Y)(或使用 C# 元组语法的任何其他元组类型)

这些类型在元数据中没有直接表示。它们包括描述类型的注释。在所有情况下,您都可以使用底层类型:

  • object 代替 dynamic

  • string 代替 string?

  • ValueTuple<int, int> 代替 (int X, int Y)

以下是使用泛型属性的示例:

using System;


[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute<T> : Attribute
{
    public MyAttribute()
{
        Value = default(T);
    }


    public T Value { get; }
}


public class MyClass
{
    [MyAttribute<string>()]
    public void MyMethod1()
{
        Console.WriteLine("MyMethod1");
    }


    [MyAttribute<int>()]
    public void MyMethod2()
{
        Console.WriteLine("MyMethod2");
    }
}


class Program
{
    static void Main(string[] args)
{
        var methods = typeof(MyClass).GetMethods();
        foreach (var method in methods)
        {
            var attributes = method.GetCustomAttributes(false);
            foreach (var attribute in attributes)
            {
                if (attribute is MyAttribute<string> myStringAttribute)
                {
                    Console.WriteLine($"Method {method.Name} has MyAttribute<string> with value {myStringAttribute.Value}");
                }
                else if (attribute is MyAttribute<int> myIntAttribute)
                {
                    Console.WriteLine($"Method {method.Name} has MyAttribute<int> with value {myIntAttribute.Value}");
                }
            }
        }
    }
}

接下来,让我们更深入地了解如何使用泛型属性来声明具有不同类型参数的属性。假设我们有一个 Person 类,它有一个属性 Age,我们希望使用泛型属性来限制其属性值的类型。

public class Person
{
    [TypeCheck(typeof(int))]
    public int Age { get; set; }
}


[AttributeUsage(AttributeTargets.Property)]
public class TypeCheckAttribute<T> : Attribute
{
    public TypeCheckAttribute()
{
        TypeToCheck = typeof(T);
    }


    public Type TypeToCheck { get; }
}

上述代码中,我们声明了一个 TypeCheckAttribute 泛型属性,它使用 typeof 运算符来获取属性值的类型。然后,我们将此属性应用于 Person 类的 Age 属性。在此示例中,Age 属性必须是 int 类型。

接下来,让我们使用另一个示例来说明泛型属性的用途。假设我们有一个类 Student,它有两个属性:Name 和 Age。我们希望使用泛型属性来限制 Name 属性的值必须是字符串类型,并将 Age 属性的值限制为整数类型。以下是代码示例:

public class Student
{
    [TypeCheck(typeof(string))]
    public string Name { get; set; }


    [TypeCheck(typeof(int))]
    public int Age { get; set; }
}


[AttributeUsage(AttributeTargets.Property)]
public class TypeCheckAttribute<T> : Attribute
{
    public TypeCheckAttribute()
{
        TypeToCheck = typeof(T);
    }


    public Type TypeToCheck { get; }
}

在上述代码中,我们声明了一个泛型属性 TypeCheckAttribute,它使用 typeof 运算符来获取属性值的类型。然后,我们将此属性应用于 Student 类的 Name 和 Age 属性。在此示例中,Name 属性必须是 string 类型,Age 属性必须是 int 类型。

最后,让我们看一下如何在运行时使用泛型属性。在以下示例中,我们使用反射获取 Student 类型的属性,并检查它们是否带有 TypeCheckAttribute 泛型属性。如果找到此属性,则检查其 TypeToCheck 属性,以确保属性值的类型符合要求。

class Program
{
    static void Main(string[] args)
    {
        var student = new Student { Name = "John Doe", Age = 25 };
        var properties = typeof(Student).GetProperties();
        foreach (var property in properties)
        {
            var attributes = property.GetCustomAttributes(false);
            foreach (var attribute in attributes)
            {
                if (attribute is TypeCheckAttribute<int> && property.PropertyType != typeof(int))
                {
                    Console.WriteLine($"{property.Name} must be of type {typeof(int)}");
                }
                else if (attribute is TypeCheckAttribute<string> && property.PropertyType != typeof(string))
                {
                    Console.WriteLine($"{property.Name} must be of type {typeof(string)}");
                }
            }
        }
    }
}

在上述示例中,我们创建了一个 Student 实例,然后使用反射获取其属性。我们遍历属性,并检查它们是否带有 TypeCheckAttribute 泛型属性。如果找到此属性,则我们检查其 TypeToCheck 属性,以确保属性值的类型符合要求。

以上就是泛型属性的介绍和示例。泛型属性是一种强大的特性,它可以帮助开发人员更方便地创建属性,并限制属性值的类型。使用泛型属性,开发人员可以轻松地创建具有不同类型参数的属性,并在运行时对其进行检查。

版权声明:本文来源于网络收集或网友供稿,仅供学习交流之用,如有侵权,请留言转告小编立即删除。

- EOF -

技术群:添加小编微信dotnet999

公众号:dotnet讲堂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值