Restringir atributo personalizado para que ele possa ser aplicada apenas a tipos específicos em C #?

StackOverflow https://stackoverflow.com/questions/1021190

  •  06-07-2019
  •  | 
  •  

Pergunta

Eu tenho um atributo personalizado que é aplicado às propriedades de classe e da própria classe. Agora todas as classes que devem ser aplicados meu atributo personalizado são derivados de uma única classe base.

Como posso restringir o meu atributo personalizado para que ele possa ser aplicado a apenas essas classes, que deve derivar de minha classe base? Como posso fazer isso?

Foi útil?

Solução

Droga, eu odeio quando me provar que estou errado ... ele funciona se você definir o atributo como um protegido tipo aninhada da base de classe:

abstract class MyBase {
    [AttributeUsage(AttributeTargets.Property)]
    protected sealed class SpecialAttribute : Attribute {}
}

class ShouldBeValid : MyBase {
    [Special]
    public int Foo { get; set; }
}
class ShouldBeInvalid {
    [Special] // type or namespace not found
    [MyBase.Special] // inaccessible due to protection level
    public int Bar{ get; set; }
}

(resposta original)

Você não pode fazer isso -. Pelo menos, não em tempo de compilação

Os atributos podem ser restrito (por exmaple) para "classe", "struct", "método", "campo", etc - mas nada mais granular

.

Claro, desde que atributos não fazem nada por si mesmos (ignorando PostSharp), eles vão ser inerte em outros tipos (e inerte em seus tipos, a menos que você adicionar algum código para olhar para os atributos em tempo de execução).

Você pode escrever uma regra FxCop, mas que parece um exagero.

Eu me pergunto, no entanto, se um atributo é a melhor escolha:

Agora, todas as classes que devem ser aplicados meu atributo personalizado são derivados de uma única classe base.

Se eles deve aplicar o seu atributo personalizado, talvez uma abstract (ou talvez apenas virtual) Propriedade / método seria uma escolha melhor?

abstract class MyBase {
    protected abstract string GetSomeMagicValue {get;}
}
class MyActualType : MyBase {
    protected override string GetSomeMagicValue {get {return "Foo";}}
}

Outras dicas

Eu não estou ciente de qualquer maneira de fazer isso com atributos personalizados.
A melhor maneira seria a de obter as classes para implementar uma interface com uma restrição genérica

para

class MyAttribute
{
     // put whatever custom data you want in here
}

interface IAttributeService<T> where T : MyBaseClass
{
     MyAttribute Value{get;}
}

então a sua classe base faria isso

class MyBaseClass : IAttributeService<MyBaseClass>
{
     private MyAttribute m_attrib;

     IAttributeService<MyClass>.Value
     {
         get {return m_attrib;}
     }
}

Dessa forma, o compilador irá impor a restrição em tempo de compilação para que apenas as classes
derivada de MyBaseClass pode implementar a interface.
Eu fiz isso bastante extensível através da definição de uma classe MyAttribute mas você poderia, claro, apenas retornar uma string ou um booleano se necessário algo mais simples

Também fiz o membro tão privado MyAttribute que classes derivadas não poderia vê-lo e alterá-lo, mas poderia fazê-lo protegido e permitir o acesso classes derivadas, se você quisesse.

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