【问题标题】:Improve property monitoring code?改进物业监控代码?
【发布时间】:2011-01-16 09:39:07
【问题描述】:

我在我正在开发的 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,所以我不知道该怎么做。也许使用闭包和lambda表达式?早些时候有人建议我这样做,但我不知道该怎么做。还有其他方法可以改善吗?

谢谢

【问题讨论】:

    标签: c# reflection properties closures


    【解决方案1】:

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

    这样,你就可以写出:

     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”工作,因为你需要有一些方法来删除委托,你可能想匿名定义它(就像我在上面所做的那样)。

    【讨论】:

      【解决方案2】:

      你为什么不使用INotifyPropertyChanged 接口而只是触发 Monitor 类中的事件,像这样......假设你的对象实现了接口......并且你的对象中的每个属性都会引发“PropertyChanged”事件使用指示值的参数...这样,这将是一个“一劳永逸”的解决方案,而不是循环遍历列表...当您使用“RenderWindow”作为“Initialize”的参数调用实例化“Monitor”时。另请注意,“Property”类稍作修改,以包含一个 get 访问器以返回相关对象...

      公共静态类监视器 { 私有静态列表监控对象; 私有静态渲染窗口_app; 公共静态无效初始化(渲染窗口应用程序) { 监控对象 = 新列表(); } 公共静态无效观察(对象o) { 监控对象.Add(o); o.PropertyChanged += new EventHandler(monitor_PropertyChanged); } 公共静态无效Unwatch(对象o) { o.PropertyChanged -= new EventHandler(monitor_PropertyChanged); 监控对象.Remove(o); } 公共静态监视器_PropertyChanged(对象发送者,PropertyChangedEventArgs e){ // 不是实际代码,我是在游戏中实际绘制的 Console.WriteLine(e.SomeValue); } 公共静态无效绘制(渲染窗口应用程序) { //不是实际代码,我是在游戏中实际绘制的 foreach(受监控对象中的对象 o) Console.WriteLine(o.ToString()); } } 公共类属性 { 私有对象 obj; 私有属性信息属性信息; 公共对象 PropObj{ 得到{返回这个.obj; } } 公共覆盖字符串 ToS​​tring() { return propertyInfo.Name + ":" + propertyInfo.GetValue(obj, null).ToString(); } 公共属性(对象o,字符串属性) { 对象 = o; propertyInfo = o.GetType().GetProperty(property); } }

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-15
        • 1970-01-01
        • 2017-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多