Restringir atributo personalizado para que ele possa ser aplicada apenas a tipos específicos em C #?
-
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?
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.