Why does C# forbid generic attribute types?
这将导致编译时异常:
1 2 3 4 5 6 7 8 9 10 | public sealed class ValidatesAttribute<T> : Attribute { } [Validates<string>] public static class StringValidation { } |
我意识到C不支持通用属性。然而,经过多次谷歌搜索,我似乎找不到原因。
有人知道为什么泛型类型不能从
嗯,我不能回答为什么它不可用,但我可以确认这不是一个CLI问题。cli规范没有提到它(据我所见),如果直接使用il,可以创建一个通用属性。C 3规范中禁止它的部分——第10.1.4节"类基础规范"没有给出任何理由。
注释的ECMA C_2规范也没有提供任何有用的信息,尽管它提供了一个不允许的示例。
我的标注C 3规格的副本明天就要到了…我看看是否能提供更多的信息。无论如何,这绝对是一个语言决定,而不是运行时决定。
编辑:来自EricLippert的回答(意译):没有特别的原因,除了为了避免语言和编译器的复杂性,对于一个没有多大价值的用例。
属性在编译时修饰类,但泛型类直到运行时才接收其最终类型信息。由于该属性会影响编译,因此它必须在编译时"完成"。
有关详细信息,请参阅此msdn文章。
我不知道为什么不允许这样做,但这是一个可能的解决办法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [AttributeUsage(AttributeTargets.Class)] public class ClassDescriptionAttribute : Attribute { public ClassDescriptionAttribute(Type KeyDataType) { _KeyDataType = KeyDataType; } public Type KeyDataType { get { return _KeyDataType; } } private Type _KeyDataType; } [ClassDescriptionAttribute(typeof(string))] class Program { .... } |
这不是真正的通用的,您仍然需要为每种类型编写特定的属性类,但是您可能能够使用通用的基本接口来进行一些防御性的编码,编写比其他要求更少的代码,获得多态性的好处等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //an interface which means it can't have its own implementation. //You might need to use extension methods on this interface for that. public interface ValidatesAttribute<T> { T Value { get; } //or whatever that is bool IsValid { get; } //etc } public class ValidatesStringAttribute : Attribute, ValidatesAttribute<string> { //... } public class ValidatesIntAttribute : Attribute, ValidatesAttribute<int> { //... } [ValidatesString] public static class StringValidation { } [ValidatesInt] public static class IntValidation { } |
这是一个很好的问题。根据我对属性的经验,我认为约束已经到位,因为当考虑属性时,它将创建一个条件,在该条件下,您必须检查所有可能的类型排列:
在我看来,如果根据类型需要自定义验证,则属性可能不是最佳方法。
也许采用
我的解决方法是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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; } |
这不是当前的C语言功能,但是有很多关于官方C语言报告的讨论。
从一些会议笔记中:
Even though this would work in principle, there are bugs in most
versions of the runtime so that it wouldn't work correctly (it was
never exercised).We need a mechanism to understand which target runtime it works on. We
need that for many things, and are currently looking at that. Until
then, we can't take it.Candidate for a major C# version, if we can make a sufficient number
of runtime versions deal with it.