Объединение нескольких атрибутов в один атрибут

на элементе управления я использую несколько свойств атрибута:

[Browsable(false)]
[Bindable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Obsolete("", true)]
public new Boolean AllowDrop;

Я использую эти свойства во многих других свойствах элемента управления.

мне интересно, есть ли способ уменьшить количество кода для записи каждый раз.

было бы неплохо, если бы я мог объединить несколько атрибутов такой:

[Hidden(true)]
public new Boolean AllowDrop;

здесь Hidden свойство будет включать все атрибуты выше. Так что есть только 1 строка код.

может быть, есть также способ объединить атрибуты в макрос или что-то еще?

Я знаю, что есть другие способы скрыть свойства, но я выбрал способ использования атрибутов.

спасибо

1 ответов


объединение атрибутов может быть значимым для контекста, который использует и интерпретирует атрибуты. Например, для контекстов, использующих механизмы описания типов .Net, можно настроить описание типа, которое .Net возвращает потребителям.

можно предоставить пользовательские метаданные для типов с помощью стандартного механизма .Net для этой цели, зарегистрировав пользовательский дескриптор типа для вашего объекта.

идея будет работать таким образом, вы создаете настраиваемый дескриптор типа для вашего типа. В пользовательском дескрипторе типа возвращаются пользовательские дескрипторы свойств для свойств типа, а в дескрипторе свойства возвращается пользовательский набор атрибутов для свойства.

подход требует больше кода, но это действительно интересно и имеет некоторые хорошие идеи о том, чтобы предоставить пользовательские метаданные для вашего типа:

Интерфейс IMetedataAttribute

использование обеспечивает стандартный способ создания MetaDataAttribues. Каждый attriute, который реализует этот интерфейс, будет использоваться как метаданные, а не атрибут, тот, который он возвращает в Process метод будет использоваться:

public interface IMetadatAttribute
{
    Attribute[] Process();
}

Образец MetadataAttribue

это пример атрибута метаданных, который возвращает некоторый атрибут при обработке атрибута:

public class MySampleMetadataAttribue : 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;
    }
}

Дескриптор Свойства

этот класс будет используется дескриптором пользовательского типа для предоставления настраиваемого списка атрибутов свойства:

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

Дескриптор Типа

это дескриптор типа, который предоставляет пользовательское описание для вашего типа. В этом примере он использует пользовательские дескрипторы propertuy для предоставления пользовательских атрибутов, заданных для свойств вашего класса:

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

Поставщик Typedescriptor

этот класс будет использоваться в атрибут над типом, чтобы ввести пользовательский дескриптор типа, который мы создали в качестве движка метаданных для типа:

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

Образец Класс

вот мой образец класса, который его Name свойство оформляется с помощью MySampleMetadataAttribute и сам класс зарегистрирован для использования нашего поставщика пользовательских дескрипторов типов:

[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
public class MySampleClass
{
    public int Id { get; set; }
    [MySampleMetadataAttribue]
    [DisplayName("My Name")]
    public string Name { get; set; }
}

чтобы увидеть результат, достаточно создать экземпляр класса и увидеть результат в PropertyGrid:

var o = new MySampleClass();
this.propertyGrid1.SelectedObject = o;

некоторые заметки об ответе

  • вероятно, это не так просто, как вы ожидали для такой задачи. Но это работает.
  • это длинный ответ, но содержит полный рабочий пример того, как вы можете применять дескрипторы типов к своим типам для предоставления пользовательских метаданных.
  • подход не будет работать для двигателей, которые используют отражение вместо описания типа. Но это полностью работает, например PropertyGrid управление, которое работает с описанием типа.