Улучшить код мониторинга свойств? - PullRequest
5 голосов
/ 13 февраля 2010

Я сделал класс отладки утилиты в игре на 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 #, я не знаю, как бы я это сделал. Может быть, используя замыкания и выражения лямбад? Мне предлагали это раньше, но я не уверен, как это сделать. Есть ли другие способы улучшить это?

Спасибо

Ответы [ 2 ]

5 голосов
/ 13 февраля 2010

Лично я бы переделал ваш класс 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 голос
/ 13 февраля 2010

Почему вы не используете INotifyPropertyChanged интерфейс и просто запускаете события в классе Monitor, что-то вроде этого ... предположим, что ваши объекты реализуют интерфейс ... и каждое свойство в ваших объектах вызываетСобытие 'PropertyChanged' с параметрами, указывающими значения ... таким образом, это будет решение «забей и забудь» вместо циклического перемещения по списку ... когда вы вызываете экземпляр «Monitor» с «RenderWindow», используемым как параметр дляИнициализировать.Также обратите внимание, что класс «Свойство» немного изменен, чтобы включить метод доступа 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);
  }
 }

Надеюсь, это поможет, С уважением, Том.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...