¿Restringir el atributo personalizado para que pueda aplicarse solo a tipos específicos en C #?

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

  •  06-07-2019
  •  | 
  •  

Pregunta

Tengo un atributo personalizado que se aplica a las propiedades de la clase y a la clase misma. Ahora todas las clases que deben aplicar mi atributo personalizado se derivan de una sola clase base.

¿Cómo puedo restringir mi Atributo personalizado para que pueda aplicarse solo a esas clases, que deben derivarse de mi clase base? ¿Cómo hago esto?

¿Fue útil?

Solución

Maldición, odio cuando demuestro que estoy equivocado ... funciona si define el atributo como un tipo anidado protegido de la clase base:

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

(respuesta original)

No puede hacer esto, al menos, no en tiempo de compilación.

Los atributos se pueden restringir (por ejemplo) a "clase", "estructura", "método", "campo", etc., pero nada más granular.

Por supuesto, dado que los atributos no hacen nada por sí mismos (ignorando PostSharp), serán inertes en otros tipos (e inertes en sus tipos a menos que agregue algún código para ver los atributos en tiempo de ejecución).

Podría escribir una regla FxCop, pero eso parece excesivo.

Sin embargo, me pregunto si un atributo es la mejor opción:

  

Ahora todas las clases que deben aplicar mi atributo personalizado se derivan de una sola clase base.

Si deben aplicar su atributo personalizado, tal vez una propiedad / método abstract (o tal vez solo virtual ) sería una mejor opción.

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

Otros consejos

No conozco ninguna forma de hacer esto con atributos personalizados.
Una mejor manera sería hacer que las clases implementen una interfaz con una restricción genérica

entonces

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

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

entonces tu clase base haría esto

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

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

De esa forma, el compilador impondrá la restricción en tiempo de compilación para que solo las clases
derivado de MyBaseClass puede implementar la interfaz.
Lo hice bastante extensible definiendo una clase MyAttribute pero, por supuesto, podría devolver una cadena o un bool si necesita algo más simple

También hice privado al miembro MyAttribute para que las clases derivadas no pudieran verlo y cambiarlo, pero podrían protegerlo y permitir el acceso a las clases derivadas si así lo desearan.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top