这会导致编译时异常:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

我意识到c#不支持泛型属性。然而,在谷歌搜索了很多次之后,我似乎找不到原因。

有人知道为什么泛型类型不能从Attribute派生吗?什么理论吗?


当前回答

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

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

其他回答

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

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

我的变通方法是这样的:

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文章。

好吧,我不能回答为什么它不可用,但我可以确认这不是CLI的问题。CLI规范没有提到它(据我所知),如果你直接使用IL,你可以创建一个通用属性。c# 3规范中禁止它的部分——10.1.4节“类基规范”并没有给出任何理由。

注释的ECMA c# 2规范也没有提供任何有用的信息,尽管它提供了一个不允许的示例。

我的带注释的c# 3规范应该明天就能到…我看看能不能提供更多信息。无论如何,这绝对是一个语言决定,而不是运行时决定。

编辑:Eric Lippert的回答(转述):没有特别的原因,只是为了避免语言和编译器的复杂性,这并没有增加多少价值。

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

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

}