首页 文章

为什么C#禁止通用属性类型?

提问于
浏览
458

这会导致编译时异常:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

我意识到C#不支持通用属性 . 然而,经过大量的谷歌搜索,我似乎无法找到原因 .

有谁知道为什么泛型类型不能从 Attribute 派生?任何理论?

6 回答

  • 320

    我不知道为什么不允许,但这是一种可行的解决方法

    [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
    {
        ....
    }
    
  • 76

    这个问题问得好 . 根据我对属性的体验,我认为约束已到位,因为在反映属性时,它会创建一个条件,您必须检查所有可能的类型排列: typeof(Validates<string>) ,_ typeof(Validates<SomeCustomType>) 等...

    在我看来,如果根据类型需要自定义验证,属性可能不是最好的方法 .

    也许一个接受 SomeCustomValidationDelegateISomeCustomValidator 作为参数的验证类将是一种更好的方法 .

  • 17

    我的解决方法是这样的:

    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; }
    
  • 8

    属性在编译时修饰一个类,但泛型类在运行时之前不会收到它的最终类型信息 . 由于该属性可能会影响编译,因此必须在编译时“完成” .

    有关更多信息,请参见MSDN article .

  • 11

    好吧,我可以't answer why it'不可用,但我可以确认它提到它(据我所见),如果你直接使用IL,你可以创建一个通用属性 . 禁止它的C#3规范的一部分 - 第10.1.4节"Class base specification"没有给出任何理由 .

    带注释的ECMA C#2规范也没有给出任何有用的信息,尽管它确实提供了一个不允许的例子 .

    我的带注释的C#3规范的副本应该明天到达......我会看看是否会提供更多信息 . 无论如何,它绝对是一种语言决定而不是运行时决定 .

    编辑:Eric Lippert的答案(释义):没有特别的原因,除了避免语言和编译器的复杂性,用于不增加太多 Value 的用例 .

  • 1

    这不是真正的通用,你仍然需要为每种类型编写特定的属性类,但是你可以使用通用的基本接口来编写一些防御性的代码,编写比其他要求更少的代码,获得多态性等的好处 .

    //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
    {
    
    }
    

相关问题