2011-10-09 12 views
35

Czy można ustawić delegata jako parametr atrybutu?Czy możliwe jest posiadanie delegata jako parametru atrybutu?

Jak to:

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

A jeśli jej nie możliwe, jakie są sensowne alternatywy?

Odpowiedz

29

Nie, nie można mieć delegata jako parametru konstruktora atrybutu. Zobacz dostępne typy: Attribute parameter types
Jako obejście (choć to hacky i podatne na błędy) można utworzyć delegate with reflection:

[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

W rzeczywistości jest to dobre obejście. Zbudowałem interfejs speficic do tego, ale delegat jest o wiele łatwiejszy. Dzięki! –

+0

To obejście, ale nie dobre. Dokładnie tak, jak powiedział @nemesv - jest hackowaty i podatny na błędy, ponieważ jeśli zmienisz nazwę metody GetConnection na inną, używając menu refactor, ciąg "GetConnection" nie zostanie automatycznie zmieniony. – prostynick

+0

Czy istnieje możliwość w C# ręcznie ograniczyć typ argumentów konstruktora? Nie słyszałem o tym czegoś, ale jak widzimy w typie "Atrybut" jest to możliwe. W jaki sposób? – monstr

9

Inne możliwe obejście jest tworzenie Abstrakcyjny typ bazowy atrybutu metody abstrakcyjnej pasujących definicji delegata, a następnie implementacja metody w betonie Klasa atrybutu.

Posiada następujące zalety:

  • Adnotacja jest bardziej zwięzły i czyste (DSL podobne)
  • Nie odbicie
  • Łatwe ponowne

Przykład:

[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 
{ 
} 
1

Rozwiązałem to, używając enum i tablica map delegatów. Chociaż bardzo podoba mi się pomysł wykorzystania dziedziczenia, w moim scenariuszu wymagałoby to napisania kilku lekcji dla dzieci, aby robić stosunkowo proste rzeczy. To powinno być również refaktowalne. Jedyną wadą jest to, że musisz upewnić się, że indeks delegata w tablicy odpowiada wartości wyliczenia.

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); 
} 
Powiązane problemy