Por que o C # proíbe tipos de atributos genéricos?

Isso causa uma exceção em tempo de compilation:

public sealed class ValidatesAttribute : Attribute { } [Validates] public static class StringValidation { } 

Eu percebo que o C # não suporta atributos genéricos. No entanto, depois de muito pesquisando, não consigo encontrar o motivo.

Alguém sabe por que tipos genéricos não podem derivar de Attribute ? Alguma teoria?

Bem, não posso responder por que não está disponível, mas posso confirmar que não é um problema do CLI. A especificação CLI não menciona (até onde eu posso ver) e se você usa o IL diretamente você pode criar um atributo genérico. A parte da especificação C # 3 que a proíbe – seção 10.1.4 “Especificação da base da class” não fornece nenhuma justificativa.

A especificação anotada do ECMA C # 2 também não fornece informações úteis, embora forneça um exemplo do que não é permitido.

Minha cópia da especificação anotada do C # 3 deve chegar amanhã … Vou ver se isso dá mais alguma informação. De qualquer forma, é definitivamente uma decisão de linguagem, em vez de uma decisão de tempo de execução.

EDIT: Resposta de Eric Lippert (parafraseada): nenhuma razão em particular, exceto para evitar a complexidade na linguagem e no compilador para um caso de uso que não agrega muito valor.

Um atributo decora uma class em tempo de compilation, mas uma class genérica não recebe suas informações de tipo final até o tempo de execução. Como o atributo pode afetar a compilation, ele deve estar “completo” em tempo de compilation.

Veja este artigo do MSDN para mais informações.

Eu não sei porque não é permitido, mas esta é uma solução possível

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

Isso não é realmente genérico e você ainda tem que escrever uma class de atributo específica por tipo, mas você pode usar uma interface base genérica para codificar um pouco defensivamente, escrever código menor do que o exigido, obter benefícios de polymorphism etc.

 //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 Value { get; } //or whatever that is bool IsValid { get; } //etc } public class ValidatesStringAttribute : Attribute, ValidatesAttribute { //... } public class ValidatesIntAttribute : Attribute, ValidatesAttribute { //... } [ValidatesString] public static class StringValidation { } [ValidatesInt] public static class IntValidation { } 

Esta é uma pergunta muito boa. Na minha experiência com atributos, acho que a restrição está em vigor porque ao refletir sobre um atributo ele criaria uma condição na qual você teria que verificar todas as permutações de tipos possíveis: typeof(Validates) , typeof(Validates) , etc …

Na minha opinião, se uma validação personalizada for necessária, dependendo do tipo, um atributo pode não ser a melhor abordagem.

Talvez uma class de validação que considere um SomeCustomValidationDelegate ou um ISomeCustomValidator como um parâmetro seja uma abordagem melhor.

Minha solução é algo assim:

 public class DistinctType1IdValidation : ValidationAttribute { private readonly DistinctValidator validator; public DistinctIdValidation() { validator = new DistinctValidator(x=>x.Id); } public override bool IsValid(object value) { return validator.IsValid(value); } } public class DistinctType2NameValidation : ValidationAttribute { private readonly DistinctValidator validator; public DistinctType2NameValidation() { validator = new DistinctValidator(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; }