这会导致编译时异常:
public sealed class ValidatesAttribute<T> : Attribute
{
}
[Validates<string>]
public static class StringValidation
{
}
我意识到c#不支持泛型属性。然而,在谷歌搜索了很多次之后,我似乎找不到原因。
有人知道为什么泛型类型不能从Attribute派生吗?什么理论吗?
这会导致编译时异常:
public sealed class ValidatesAttribute<T> : Attribute
{
}
[Validates<string>]
public static class StringValidation
{
}
我意识到c#不支持泛型属性。然而,在谷歌搜索了很多次之后,我似乎找不到原因。
有人知道为什么泛型类型不能从Attribute派生吗?什么理论吗?
当前回答
泛型属性从。net 7和c# 11开始支持(在。net 6和c# 10的预览中)。
其他回答
这目前还不是c#语言的特性,但是关于官方的c#语言回购有很多讨论。
以下是一些会议记录:
尽管这在原则上可行,但大多数都存在漏洞 运行时的版本,使它不能正常工作(它是 没有执行)。 我们需要一种机制来理解它工作在哪个目标运行时上。我们 很多事情都需要它,目前正在考虑。直到 那么,我们就不能接受了。 一个主要的c#版本的候选,如果我们能做出足够的数量 的运行时版本处理它。
我的变通方法是这样的:
public class DistinctType1IdValidation : ValidationAttribute
{
private readonly DistinctValidator<Type1> validator;
public DistinctIdValidation()
{
validator = new DistinctValidator<Type1>(x=>x.Id);
}
public override bool IsValid(object value)
{
return validator.IsValid(value);
}
}
public class DistinctType2NameValidation : ValidationAttribute
{
private readonly DistinctValidator<Type2> validator;
public DistinctType2NameValidation()
{
validator = new DistinctValidator<Type2>(x=>x.Name);
}
public override bool IsValid(object value)
{
return validator.IsValid(value);
}
}
...
[DataMember, DistinctType1IdValidation ]
public Type1[] Items { get; set; }
[DataMember, DistinctType2NameValidation ]
public Type2[] Items { get; set; }
属性在编译时修饰类,但泛型类直到运行时才接收其最终类型信息。因为属性会影响编译,所以它必须在编译时是“完整的”。
有关更多信息,请参阅MSDN文章。
这是一个非常好的问题。根据我使用属性的经验,我认为约束是合适的,因为当反射一个属性时,它会创建一个条件,在这种条件下,您必须检查所有可能的类型排列:typeof(Validates<string>), typeof(Validates<SomeCustomType>),等等……
在我看来,如果需要根据类型进行自定义验证,那么属性可能不是最好的方法。
也许采用SomeCustomValidationDelegate或ISomeCustomValidator作为参数的验证类是更好的方法。
泛型属性从c# 11开始可用。现在,这是可能的:
[GenericAttribute<int>()]
public int Method();
然而,这还不可能:
[GenericAttribute<T>()]
public int Method<T>(T param);
T在编译时是未知的。
同时,
The type arguments must satisfy the same restrictions as the typeof operator. Types that require metadata annotations aren't allowed. For example, the following types aren't allowed as the type parameter: dynamic string? (or any nullable reference type) (int X, int Y) (or any other tuple types using C# tuple syntax). These types aren't directly represented in metadata. They include annotations that describe the type. In all cases, you can use the underlying type instead: object for dynamic. string instead of string?. ValueTuple<int, int> instead of (int X, int Y).
来源:https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11 generic-attributes