改善财产监控代码?

时间:2010-02-13 01:32:09

标签: c# reflection properties closures

我在C#游戏中制作了一个实用程序调试类,我正在努力监视和观察属性值。是这样的:

public static class Monitor
{
  private static List<object> monitoredObjects;

  public static void Initialize()
  {
   monitoredObjects = new List<object>();

  }

  public static void Watch(object o)
  {
   monitoredObjects.Add(o);
  }

  public static void Unwatch(object o)
  {
   monitoredObjects.Remove(o);
  }

  public static void Draw(RenderWindow app)
  {
                    //Not actual code, I actually draw this in game
   foreach (object o in monitoredObjects)
    Console.WriteLine(o.ToString());
  }
 }

 public class Property
 {
  private object obj;
  private PropertyInfo propertyInfo;

  public override string ToString()
  {
   return propertyInfo.Name + ": " + propertyInfo.GetValue(obj, null).ToString();
  }

  public Property(object o, string property)
  {
   obj = o;
   propertyInfo = o.GetType().GetProperty(property);
  }
 }

现在为了监控一个属性,比如我的游戏的FPS,我必须这样做

Monitor.Watch(new Property(Game, "FPS"));

难道没有办法以某种方式使这个更简单使用?理想情况下,我希望能够做到

Monitor.Watch(Game.FPS);

但是因为我们不能在C#中store pointers to value types,所以我不知道如何做到这一点。也许使用闭包和lambada表达式?我之前提出过这个建议,但我不知道该怎么办。还有其他方法可以改善这个吗?

由于

2 个答案:

答案 0 :(得分:5)

就我个人而言,我要做的是重写您的Monitor类以接受Func<string>作为输入,并返回一个监视句柄,可用于“取消监视”该类。

通过这样做,你可以写:

 var handle = Monitor.Watch( () => Game.FPS.ToString() );
 // later
 Monitor.Unwatch(handle);

这看起来像是:

public static class Monitor
{
    private static Dictionary<IMonitorHandle, Func<string>> monitoredObjects;

    public static void Initialize()
    {
        monitoredObjects = new Dictionary<IMonitorHandle, Func<string>>();
    }

    public static IMonitorHandle Watch(Func<string> o)
    {
        var handle = new MonitorHandle(o);
        monitoredObjects.Add(handle, o);
        return handle;
    }

    public static void Unwatch(IMonitorHandle handle)
    {
        monitoredObjects.Remove(handle);
    }

    public static void Draw(RenderWindow app)
    {
        //Not actual code, I actually draw this in game
        foreach (object o in monitoredObjects.Values)
           Console.WriteLine(o()); // Execute to get value...
    }
}

你需要为句柄实现一些接口 - 但这确实可以是任何东西,因为它只是一个用作哈希表查找的对象,允许取消订阅。你只需要这样就可以让“Unwatch”工作,因为你需要有一些方法来删除你可能想要匿名定义的委托(正如我上面所做的那样)。

答案 1 :(得分:1)

为什么你没有使用INotifyPropertyChanged接口而只是触发Monitor类中的事件,就像这样......假设你的对象实现了接口......并且对象中的每个属性都会引发'PropertyChanged '带有参数指示值的事件......以这种方式,它将是一个解雇并忘记解决方案,而不是循环遍历列表...当您调用实例化'监视'时,'RenderWindow'用作'初始化'的参数。另请注意,“Property”类稍作修改,以包含一个get访问器来返回有问题的对象......

public static class Monitor
{
  private static List monitoredObjects;
  private static RenderWindow _app;

  public static void Initialize(RenderWindow app)
  {
   monitoredObjects = new List();

  }

  public static void Watch(object o)
  {
   monitoredObjects.Add(o);
   o.PropertyChanged += new EventHandler(monitor_PropertyChanged);
  }

  public static void Unwatch(object o)
  {
   o.PropertyChanged -= new EventHandler(monitor_PropertyChanged);
   monitoredObjects.Remove(o);
  }

  public static monitor_PropertyChanged(object sender, PropertyChangedEventArgs e){
    // Not actual code, I actually draw this in game
    Console.WriteLine(e.SomeValue);
  }

  public static void Draw(RenderWindow app)
  {
                    //Not actual code, I actually draw this in game
   foreach (object o in monitoredObjects)
    Console.WriteLine(o.ToString());
  }
 }

 public class Property
 {
  private object obj;
  private PropertyInfo propertyInfo;

  public object PropObj{
     get{ return this.obj; }
  }

  public override string ToString()
  {
   return propertyInfo.Name + ": " + propertyInfo.GetValue(obj, null).ToString();
  }

  public Property(object o, string property)
  {
   obj = o;
   propertyInfo = o.GetType().GetProperty(property);
  }
 }

希望这有帮助, 最好的祝福, 汤姆。