Aktualizacja: @JeremyDWill słusznie wskazał, że nie można wywieść typu rodzajowego od jednego z jego parametrów ...
Jeśli myślisz o dekoratora jako „podklasy, który dodaje nowe właściwości”, ty mógłby zrobić coś takiego:
public class MyDecorator<T> : T
{
public int MyDecoratorProperty1 { get; set; }
public int MyDecoratorProperty2 { get; set; }
}
Następnie można utworzyć instancji
MyDecorator<DataBag>
i
MyDecorator<OtherClass>
itp istniejące właściwości są dostępne, ponieważ
MyDecorator<>
jest specyficzny dla typu rodzajowego argumentu, a wywodzi się z tej klasy.
Można utworzyć opakowanie, które zawiera urządzony obiekt:
public class MyDecorator<T>
{
public MyDecorator(T decoratedObject)
{
this.DecoratedObject = decoratedObject;
}
public T DecoratedObject { get; private set; }
public int MyDecoratorProperty1 { get; set; }
public int MyDecoratorProperty2 { get; set; }
}
Zaletą jest to, że dotarcie do zdobionych właściwości jest proste: myObj.MyDecoratorProperty1
. Minusem jest to, że teraz trzeba przejść przez członka DecoratedObject
dostać się do obiektu bazowego:
DataBag bag = new DataBag("", null, null);
MyDecorator<DataBag> deco = new MyDecorator<DataBag>(bag);
deco.DecoratedObject.Height = 2;
Jeśli nie można podklasy z Dekoracje (trzeba obsługiwać wiele dekoratorów w czasie, powiedzmy), będziesz musiał zrobić coś w rodzaju "przywiązanej własności" ... Twoja klasa dekoratorów będzie musiała przechowywać słownik oryginalnych przedmiotów i dekorowanych właściwości. Za pomocą kilku metod rozszerzenie, można zrobić te właściwości „wyglądają” jak rodzimych członków zdobione klasy tak długo, jak wiesz typy coraz urządzone z góry (lub są skłonni do dekoracji żadnego Object):
public static class AttachedDecorator
{
private class Properties
{
public int MyDecoratorProperty1 { get; set; }
public int MyDecoratorProperty2 { get; set; }
}
private static Dictionary<object, Properties> map = new Dictionary<object, Properties>();
public static int GetMyDecoratorProperty1(object obj)
{
Properties props;
if (map.TryGetValue(obj, out props))
{
return props.MyDecoratorProperty1;
}
return -1; // or some value that makes sense if the object has no decorated property set
}
public static int GetMyDecoratorProperty2(object obj) { /* ... */ }
public static void SetMyDecoratorProperty1(object obj, int value)
{
Properties props;
if (!map.TryGetValue(obj, out props))
{
props = new Properties();
map.Add(obj, props);
}
props.MyDecoratorProperty1 = value;
}
public static void SetMyDecoratorProperty2(object obj, int value) { /* ... */ }
}
public static class DecoratorExtensions
{
private static int GetMyDecoratorProperty1(this object obj)
{
return AttachedDecorator.GetMyDecoratorProperty1(obj);
}
private static void SetMyDecoratorProperty1(this object obj, int value)
{
return AttachedDecorator.GetMyDecoratorProperty1(obj, value);
}
// ...
}
Twój kod to może wyglądać następująco:
DataBag myData = new DataBag();
myData.SetMyDecoratorProperty1(7);
Console.WriteLine("prop1: {0}", myData.GetMyDecoratorProperty1());
Zazwyczaj wszyscy dekoratorzy dziedziczą ze wspólnego interfejsu. W takim przypadku, jaki byłby ten interfejs? Jeśli jest dynamiczny, to może dekorator nie jest odpowiedni. –
Czy uważasz, że dekorator * może odziedziczyć * z 'DataBag'? Jedyny problem polega na tym, że nie można odlewać od dekoratora w dół od typu podstawowego. – McGarnagle
@dbaseman Z początku korzystałem z dziedziczenia, ale bardzo szybko doszło do sytuacji, w której potrzebnych było wiele klas o nieco innych właściwościach i metodach. – Anton