为什么C#禁止generics属性types?
这会导致编译时exception:
public sealed class ValidatesAttribute<T> : Attribute { } [Validates<string>] public static class StringValidation { }
我意识到C#不支持通用属性。 但是,经过多次Googlesearch,我似乎无法find原因。
有谁知道为什么genericstypes不能从Attribute
派生? 任何理论?
那么,我不能回答为什么它不可用,但我可以证实,这不是一个CLI问题。 CLI规范没有提到它(据我所知),如果直接使用IL,则可以创build一个通用属性。 C#3规范禁止的部分 – 第10.1.4节“类基本规范”没有给出任何理由。
注释的ECMA C#2规范也没有提供任何有用的信息,虽然它提供了一个不允许的例子。
我的注释C#3规范的副本应该明天到达…我会看看是否给出了更多的信息。 无论如何,这绝对是一个语言决定,而不是运行时间。
编辑:从埃里克·利波特(解释)答案:没有特别的原因,除了避免复杂的语言和编译器的用例,没有增加太多的价值。
一个属性在编译时装饰一个类,但是generics类直到运行时才会收到它的最终types信息。 由于该属性会影响编译,因此编译时必须“完成”。
有关更多信息,请参阅此MSDN文章 。
我不知道为什么不允许,但这是一个可能的解决方法
[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 { .... }
这不是真正的通用的,你仍然需要为每种types编写特定的属性类,但是你也许可以使用通用的基本接口来进行防御性编码,编写比其他方式要求更less的代码,获得多态性的好处等等。
//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 { }
这是一个非常好的问题。 根据我对属性的经验,我认为约束是有原因的,因为当反映一个属性时,它会创build一个条件,你必须检查所有可能的types排列: typeof(Validates<string>)
, typeof(Validates<SomeCustomType>)
等…
在我看来,如果需要自定义validation取决于types,属性可能不是最好的方法。
也许一个接受SomeCustomValidationDelegate
或ISomeCustomValidator
作为参数的validation类将是更好的方法。
我的解决方法是这样的:
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; }