c# - Combinando mĂșltiples atributos en un solo atributo
.net winforms (1)
En un control estoy usando múltiples propiedades de atributos:
[Browsable(false)]
[Bindable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Obsolete("", true)]
public new Boolean AllowDrop;
Estoy usando esas propiedades en muchas de las otras propiedades de control también.
Me pregunto si hay una manera de reducir la cantidad de código para escribir cada vez.
Sería bueno si pudiera combinar múltiples atributos como este:
[Hidden(true)]
public new Boolean AllowDrop;
Donde la propiedad
Hidden
incluiría todos los atributos anteriores.
Por lo tanto, solo hay 1 línea de código.
¿Quizás también hay una manera de combinar los atributos en una macro o algo así?
Soy consciente de que hay otras formas de ocultar propiedades, pero elegí la forma de usar los atributos.
Gracias
La combinación de atributos puede ser significativa para el contexto que usa e interpreta los atributos. Por ejemplo, para aquellos contextos que utilizan mecanismos de Descripción de tipo .Net, puede personalizar la descripción de tipo que .Net devuelve a los consumidores.
Es posible proporcionar metadatos personalizados para los tipos que utilizan el mecanismo .Net estándar para ese propósito, registrando un descriptor de tipo personalizado para su objeto.
La idea funcionará de esta manera, usted crea un descriptor de tipo personalizado para su tipo. En el descriptor de tipo personalizado, devuelve descriptores de propiedad personalizados para las propiedades de su tipo y en el descriptor de propiedad, devuelve un conjunto personalizado de atributos para la propiedad.
El enfoque requiere más código, pero es realmente interesante y comparte una buena idea sobre cómo proporcionar metadatos personalizados para sus tipos:
Interfaz IMetedataAttribute
El uso proporciona una forma estándar de crear MetaDataAttributes.
Cada atributo que implementa esta interfaz se utilizará como metadatos y, en lugar del atributo, se utilizarán aquellos que devuelve en el método de
Process
:
public interface IMetadatAttribute
{
Attribute[] Process();
}
Atributo de metadatos de muestra
Es un atributo de metadatos de muestra que devuelve algún atributo al procesar el atributo:
public class MySampleMetadataAttribute : Attribute, IMetadatAttribute
{
public Attribute[] Process()
{
var attributes = new Attribute[]{
new BrowsableAttribute(false),
new EditorBrowsableAttribute(EditorBrowsableState.Never),
new BindableAttribute(false),
new DesignerSerializationVisibilityAttribute(
DesignerSerializationVisibility.Hidden),
new ObsoleteAttribute("", true)
};
return attributes;
}
}
Descriptor de propiedad
El descriptor de tipo personalizado utilizará esta clase para proporcionar una lista personalizada de atributos para la propiedad:
public class MyPropertyDescriptor : PropertyDescriptor
{
PropertyDescriptor original;
public MyPropertyDescriptor(PropertyDescriptor originalProperty)
: base(originalProperty) { original = originalProperty;}
public override AttributeCollection Attributes
{
get
{
var attributes = base.Attributes.Cast<Attribute>();
var result = new List<Attribute>();
foreach (var item in attributes)
{
if(item is IMetadatAttribute)
{
var attrs = ((IMetadatAttribute)item).Process();
if(attrs !=null )
{
foreach (var a in attrs)
result.Add(a);
}
}
else
result.Add(item);
}
return new AttributeCollection(result.ToArray());
}
}
// Implement other properties and methods simply using return original
// The implementation is trivial like this one:
// public override Type ComponentType
// {
// get { return original.ComponentType; }
// }
}
Descriptor de tipo
Este es el descriptor de tipo que proporciona una descripción personalizada para su tipo. En este ejemplo, utiliza descriptores de propiedad personalizados para proporcionar atributos personalizados establecidos para las propiedades de su clase:
public class MyTypeDescriptor : CustomTypeDescriptor
{
ICustomTypeDescriptor original;
public MyTypeDescriptor(ICustomTypeDescriptor originalDescriptor)
: base(originalDescriptor)
{
original = originalDescriptor;
}
public override PropertyDescriptorCollection GetProperties()
{
return this.GetProperties(new Attribute[] { });
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
.Select(p => new MyPropertyDescriptor(p))
.ToArray();
return new PropertyDescriptorCollection(properties);
}
}
Proveedor de descriptor de tipo
Esta clase se usará en el atributo sobre su tipo para presentar el descriptor de tipo personalizado que creamos como motor de metadatos para el tipo:
public class MyTypeDescriptionProvider : TypeDescriptionProvider
{
public MyTypeDescriptionProvider()
: base(TypeDescriptor.GetProvider(typeof(object))) { }
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
object instance)
{
ICustomTypeDescriptor baseDescriptor = base.GetTypeDescriptor(objectType, instance);
return new MyTypeDescriptor(baseDescriptor);
}
}
Clase de muestra
Aquí está mi clase de muestra, cuya propiedad
Name
está decorada con
MySampleMetadataAttribute
y la clase en sí está registrada para usar nuestro proveedor de descriptor de tipo personalizado:
[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
public class MySampleClass
{
public int Id { get; set; }
[MySampleMetadataAttribue]
[DisplayName("My Name")]
public string Name { get; set; }
}
Para ver el resultado es suficiente crear una instancia de la clase y ver el resultado en
PropertyGrid
:
var o = new MySampleClass();
this.propertyGrid1.SelectedObject = o;
Algunas notas sobre la respuesta
- Probablemente no sea tan simple como esperaba para tal tarea. Pero está funcionando.
- Es una respuesta larga, pero contiene un ejemplo de trabajo completo de cómo puede aplicar descriptores de tipo a sus tipos para proporcionar metadatos personalizados.
-
El enfoque no funcionará para motores que usan reflexión en lugar de descripción de tipo.
Pero está funcionando completamente con, por ejemplo, el control
PropertyGrid
que funciona con la descripción del tipo.