我有这个简单的课程:
public class DataBag
{
public string UserControl { get; set; }
public string LoadMethod { get; set; }
public dynamic Params { get; set; }
public int Height { get; set; }
public DataBag(string Control,
object vars, string lm)
{
UserControl = Control;
LoadMethod = lm;
Params = vars;
Height = 0;
}
}
然后我想为它创建一个装饰器,它会添加一堆自己的属性。问题是提供访问装饰属性的最简洁和优雅的方法是什么?
到目前为止,我有两个选择:要么为装饰器中的四个装饰属性中的每一个提供一个get-set
对(看起来很潮湿,基本上是我想要避免的)或者我继承{{1}来自DataBag
,然后以某种方式设法使用DynamicObject
方法获取装饰属性(这是动态的,似乎不是在C#中做事的正确方法)。
有什么建议吗?
答案 0 :(得分:8)
实施装饰时我经常做以下。首先 - 提取装饰对象的界面并使装饰对象实现界面:
public interface IDataBag
{
string UserControl { get; set; }
string LoadMethod { get; set; }
dynamic Params { get; set; }
int Height { get; set; }
}
接下来 - 创建一个装饰器,它将所有调用委托给装饰对象(所有装饰器都将从这个装饰器继承):
public class DataBagDecorator : IDataBag
{
private IDataBag _dataBag;
public DataBagDecorator(IDataBag dataBag)
{
_dataBag = dataBag;
}
public virtual string UserControl
{
get { return _dataBag.UserControl; }
set { _dataBag.UserControl = value; }
}
// other members
}
最后 - 创建装饰器:
public class FooDataBag : DataBagDecorator
{
public FooDataBag(IDataBag dataBag)
: base(dataBag) { }
public override string UserControl
{
// added behavior
get { return "Foo" + base.UserControl; }
set { base.UserControl = value; }
}
// you don't need to override other members
}
用法:
IDataBag dataBag = new FooDataBag(new DataBag());
答案 1 :(得分:1)
更新:@JeremyDWill正确地指出你无法从其中一个参数派生泛型类型......
如果您将装饰器视为“添加新属性的子类”,您可以执行以下操作:
public class MyDecorator<T> : T
{
public int MyDecoratorProperty1 { get; set; }
public int MyDecoratorProperty2 { get; set; }
}
然后您可以创建 MyDecorator<DataBag>
和MyDecorator<OtherClass>
等实例。可以访问现有属性,因为MyDecorator<>
特定于泛型参数,并派生自该类。
您可以创建一个包含装饰对象的包装器:
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; }
}
优点是获取装饰属性很简单:myObj.MyDecoratorProperty1
。缺点是您现在必须通过DecoratedObject
成员才能到达基础对象:
DataBag bag = new DataBag("", null, null);
MyDecorator<DataBag> deco = new MyDecorator<DataBag>(bag);
deco.DecoratedObject.Height = 2;
如果你不能从装饰子类化(你需要一次支持多个装饰器,比如说),你必须做一些类似“附加属性”的东西......你的装饰者类必须保持一个原始对象字典和装饰属性。使用一些扩展方法,您可以使这些属性“看起来”像装饰类的本机成员,只要您知道提前装饰的类型(或者愿意装饰任何对象): / p>
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);
}
// ...
}
您的代码可能如下所示:
DataBag myData = new DataBag();
myData.SetMyDecoratorProperty1(7);
Console.WriteLine("prop1: {0}", myData.GetMyDecoratorProperty1());
答案 2 :(得分:1)
这是最简单的装饰方式:
public class PrettyBag : DataBag
{
public int Decoration1 { get; set; }
public int Decoration2 { get; set; }
}
如果要创建外观并隐藏某些DataBag属性而不是仅添加属性,则可以使DataBag的成员受到保护。
使用接口可以:
public interface IDataBag
{
...
}
public class DataBag : IDataBag
{
...
}
public interface IPrettyBag : IDataBag
{
int Decoration1 { get; set; }
int Decoration2 { get; set; }
}
public class BigBag : IPrettyBag
{
public int Decoration1 { get; set; }
public int Decoration2 { get; set; }
}
public interface SmallBag : IPrettyBag
{
public int Decoration1 { get; set; }
public int Decoration2 { get; set; }
}