动态装饰c#中的对象

时间:2010-04-29 16:54:38

标签: c# decorator

是否可以轻松地动态装饰对象?

例如,假设我有List<PointF>。这个列表实际上是正弦函数的图。我想通过这些观点为每个PointF添加一个标志,告知它是否是一个高峰。

但是我不想创建一个新的扩展SpecialPointF或者其他什么,它有一个布尔属性。

判断我想要懒惰的一切,但懒惰是多么出色的想法诞生(也是糟糕的想法)

编辑:我会接受拳击解决方案以及你能想到的任何有趣的黑客攻击。没有什么可以阻止我的衍生。我只是想知道是否有更有趣的方式。

4 个答案:

答案 0 :(得分:5)

不,没有办法(具体地)你要求的东西。

假设您使用的是C#3.0+,您可以使用匿名类型来执行此操作,假设您不希望在函数之外公开信息。

var decoratedList = sourceList.Select(pt => new 
                    { 
                        IsPeak = GetIsPeak(pt), 
                        Point = pt 
                    }).ToList();

这将为您提供一个新的List<T>对象。这可能无法解决您的问题,因为您无法在单个函数调用之外扩展它,并且您正在创建 new 列表而不是修改现有的列表,但希望这会有所帮助。

答案 1 :(得分:4)

如果有一种方法可以计算每个点,你不需要为它添加一个标记,你可以使用extension方法而不必扩展它。

像PointF.isPeak();

它的作用类似于:

public static class Extensions
{
    public static bool isPeak (this PointF p)
    {
        do crazy math...

        return result;
    }
}

瞧,你在PointF课上有计算。

顺便说一句,公共静态类必须在最外层,不能嵌套。

答案 2 :(得分:3)

可能可以使用C#4.0中的新dynamic关键字和ExpandoObject构造来实现此目的,但我还没有第一手经验。据我所知,它是为了轻松解决这个问题而创建的,所以你可以说

dynamic something = new ExpandoObject();
something.Anything = "whatever you want";

相信可以动态扩展现有类型,但可能需要创建一个新的子类,这会破坏练习的整个目的。

可以使用扩展方法创建几乎相同的解决方案。 ExpandoObject在内部实现为Dictionary,但它添加了优雅的原生语法。

class Program {

   static void Main(string[] args)
   {
      PointF p = new PointF(0, 0);

      p.SetFlag(true);

      if (p.GetFlag())
         Console.WriteLine("win");
   }

}

public static class Extensions
{
   private static Dictionary<PointF, bool> flags = new Dictionary<PointF, bool>();
   public static bool GetFlag(this PointF key)
   {
      return flags[key];
      //OR return flags.ContainsKey(key) ? flags[key] : false;
   }

   public static void SetFlag(this PointF key, bool val)
   {
      flags[key] = val;
   }
}

答案 3 :(得分:2)

不,这是不可能的。

最近的只是创建一个

var decorationData = new Dictionary <Object, bool>

然后将值保存在那里。无需直接扩展类型。您甚至可以使用扩展方法来访问存储的数据,这些数据看起来就像是对象的直接属性。

public static class PointFPeakExtensions
{ 
    private static var decorationData = new Dictionary <PointF, bool>

    public static bool IsPeak (this PointF point) 
    { 
        return decorationData[point];
    } 
    public static void SetPeak (this PointF point, bool isPeak) 
    { 
        decorationData[point] = isPeak;
    } 
} 

并添加到您的编辑中:

您也可以使用仅包含装饰数据和引用类型的泛型类型来解决此问题(与类库中实现Nullable类型的方式相同)。但是,这仍然意味着您必须在使用该类型的位置更改签名(这可能不是您在查找装饰器时要执行的操作)。