Подтвердить что ты не робот

Возможно ли иметь делегат в качестве параметра атрибута?

Возможно ли иметь делегат в качестве параметра атрибута?

Вот так:

public delegate IPropertySet ConnectionPropertiesDelegate();

public static class TestDelegate
{
    public static IPropertySet GetConnection()
    {
        return new PropertySetClass();
    }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface,AllowMultiple=false,Inherited=true)]
public class WorkspaceAttribute : Attribute
{
    public ConnectionPropertiesDelegate ConnectionDelegate { get; set; }

    public WorkspaceAttribute(ConnectionPropertiesDelegate connectionDelegate)
    {
        ConnectionDelegate = connectionDelegate;
    }
}

[Workspace(TestDelegate.GetConnection)]
public class Test
{
}

И если это невозможно, каковы разумные альтернативы?

4b9b3361

Ответ 1

Нет, у вас не может быть делегата в качестве параметра конструктора атрибутов. См. Доступные типы: Типы параметров атрибутов
В качестве обходного пути (хотя он взломан и подвержен ошибкам) ​​вы можете создать делегат с отражением:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
public class WorkspaceAttribute : Attribute
{
    public ConnectionPropertiesDelegate ConnectionDelegate { get; set; }

    public WorkspaceAttribute(Type delegateType, string delegateName)
    {
         ConnectionDelegate = (ConnectionPropertiesDelegate)Delegate.CreateDelegate(delegateType, delegateType.GetMethod(delegateName));
    }
}

[Workspace(typeof(TestDelegate), "GetConnection")]
public class Test
{
}

Ответ 2

Другим возможным обходным путем является создание абстрактного базового типа атрибута с абстрактным методом, соответствующим вашему определению делегата, а затем реализация метода в конкретном классе атрибута.

Он имеет следующие преимущества:

  • Аннотации более сжатые и чистые (например, DSL)
  • Отсутствие отражения
  • Простота повторного использования

Пример:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple=false, Inherited=true)]
public abstract class GetConnectionAttribute : Attribute
{
    public abstract IPropertySet GetConnection();
}

public class GetConnectionFromPropertySetAttribute : GetConnectionAttribute
{
    public override IPropertySet GetConnection()
    {
        return new PropertySetClass();
    }
}

[GetConnectionFromPropertySet]
public class Test
{
}

Ответ 3

Я решил это, используя перечисление и массив отображения делегатов. Хотя мне очень нравится идея использования наследования, в моем сценарии, который потребовал бы, чтобы я написал несколько дочерних классов, чтобы делать относительно простые вещи. Это также должно быть рефакторизуемо. Единственным недостатком является то, что вы должны убедиться, что индекс делегата в массиве соответствует значению перечисления.

public delegate string FormatterFunc(string val);

public enum Formatter
{
    None,
    PhoneNumberFormatter
}

public static readonly FormatterFunc[] FormatterMappings = { null, PhoneNumberFormatter };

public string SomeFunction(string zzz)
{
   //The property in the attribute is named CustomFormatter
   return FormatterMappings[(int)YourAttributeHere.CustomFormatter](zzz);
}