『 再看.NET7』泛性特性使用场景

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『 再看.NET7』泛性特性使用场景相关的知识,希望对你有一定的参考价值。

使用特性,可以有效地将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联。 将特性与程序实体相关联后,可以在运行时使用反射这项技术查询特性。

https://learn.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/attributes/

上面是引自微软官方文档,关于特性的作用的描述。在.NET7中,可以给特性定义泛型了。这看起来似乎和特性的参数有矛盾,因为特性的参数是以下类型。

  • 简单类型:bool,byte,char,double,float,int,long,sbyte,short,string,uint,ulong,ushort。

  • object类型。

  • System.Type类型。

  • 枚举类型。

  • 上面类型的一维数组。

看下面的例子,定义泛型参特性,想把T当构造函数参数,也就是特性的必值参数使用,但是这里报错了,信息是:这不是有效的特性参数类型,这也就是上面说的特性参数与泛型有矛盾的地方。

/// <summary>
/// 自定义类
/// </summary>
public class MyType


/// <summary>
/// 泛型特性
/// </summary>
/// <typeparam name="T"></typeparam>
public class GenericAttribute<T> : Attribute where T : class, new()

    public GenericAttribute(T t)

    

/// <summary>
/// 使用泛型特性
/// </summary>
[Generic<MyType>(new MyType())]
public class A

其实泛型特性主要是提供声明性信息的,不能传A类型的实例对像是可以理解的,至少能把A类型这个声明性信息带入。所以这就对泛特性的使用姿势有要求了。

还是先看一下面的一个用法吧。

using System.Reflection;
using System.Text;


var person = new Person();
person.ID = 10;
person.Name = "桂素伟";
Console.WriteLine(person);


var order = new Order();
order.ID = 10;
order.Name = "批发";
order.Pirce = 12.34m;
Console.WriteLine(order);


[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class DataFormatAttribute<T> : Attribute


public interface IFormatter

    string ConvertTo(object obj);



public class JsonFormatter : IFormatter

    public string ConvertTo(object obj)
    
        return System.Text.Json.JsonSerializer.Serialize(obj);
    

public class XmlFormatter : IFormatter

    public string ConvertTo(object obj)
    
        var ser = new System.Xml.Serialization.XmlSerializer(obj.GetType());
        using var memory = new MemoryStream();
        ser.Serialize(memory, obj);
        var bytes = memory.GetBuffer();
        return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
    



public abstract class Entity

    public override string? ToString()
    
        var type = this.GetType();
        foreach (var attr in type.GetCustomAttributes(false))
        
            if (attr.GetType().IsGenericType)
            
                var pars = attr.GetType().GenericTypeArguments;
                foreach (var par in pars)
                
                    var format = Activator.CreateInstance(par) as IFormatter;
                    return format?.ConvertTo(this);
                
            
        
        return null;
    



[DataFormat<JsonFormatter>()]
public class Person : Entity

    public int ID  get; set; 
    public string? Name  get; set; 

[DataFormat<XmlFormatter>()]
public class Order : Entity

    public int ID  get; set; 
    public string? Name  get; set; 
    public decimal Pirce  get; set; 

例子很简单,就是把实体类的格式化器声明在实体定义阶段,最终通过重构ToString函数,实现对泛特性的类型参数反射和使用。由此例可以大体看出,泛型特性的T,一般是通过反射创建实例而来的,而不是通过定义实例化而来的,所以这个类型一般是使用其中的方法等功能,而非属性类的数据。

以上是关于『 再看.NET7』泛性特性使用场景的主要内容,如果未能解决你的问题,请参考以下文章

.NET6之MiniAPI(三十):结束篇(附链接)

『 再看.NET7』string的进化

『 再看.NET7』数值类型

『 再看.NET7』让json序列化体现多态

『 再看.NET7』是否数值类型

『 再看.NET7』看看required属性有什么不同