Pergunta

Isso faz com que uma exceção de tempo de compilação:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

Eu percebo que C # não suporta atributos genéricos. No entanto, depois de muito Googling, eu não consigo encontrar a razão.

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

Foi útil?

Solução

Bem, eu não posso responder por que ele não está disponível, mas eu pode confirmam que não é uma questão CLI. A especificação CLI não mencioná-lo (tanto quanto eu posso ver) e se você usar IL diretamente você pode criar um atributo genérico. A parte da especificação C # 3, que proíbe it -. Seção 10.1.4 "base especificação Classe" não dá qualquer justificação

O anotada ECMA C # 2 especificação não dá qualquer informação útil tanto, embora forneça um exemplo do que não é permitido.

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

EDIT: Resposta de Eric Lippert (parafraseado):. Nenhuma razão particular, a não ser para a complexidade evitar tanto na linguagem e compilador para um caso de uso que não acrescenta muito valor

Outras dicas

Um atributo decora uma classe em tempo de compilação, mas uma classe genérica não recebe suas informações de tipo final até a execução. Desde o atributo pode afetar compilação, que tem que ser "completo" em tempo de compilação.

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

Eu não sei por que 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
{
    ....
}

Isto não é verdadeiramente genérico e você ainda tem que escrever classe atributo específico por tipo, mas você pode ser capaz de usar uma interface base genérico para código um pouco defensiva, escrever código menor do que exigido de outra forma, obter benefícios do polimorfismo 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>
{
    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
{

}

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 que iria criar uma condição em que você teria que verificar todas as permutações de tipos possíveis: typeof(Validates<string>), typeof(Validates<SomeCustomType>), etc ...

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

Talvez uma classe de validação que leva em um SomeCustomValidationDelegate ou um ISomeCustomValidator como parâmetro seria uma abordagem melhor.

A minha solução é algo como isto:

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

Isto não é atualmente uma característica # linguagem C, no entanto há muita discussão sobre a língua oficial C # repo .

A partir algumas notas de reuniões :

Mesmo que isso iria funcionar em princípio, há erro na maioria versões do tempo de execução para que ele não iria funcionar corretamente (que era Nunca exerceu).

Precisamos de um mecanismo para entender que runtime alvo ele funciona em. Nós precisa que, para muitas coisas, e atualmente estão olhando para isso. Até então, não podemos tomá-lo.

Candidato para uma grande versão C #, se podemos fazer um número suficiente de tempo de execução versões lidar com isso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top