【问题标题】:C# Monitoring closed-source classes and primitives for value changesC# 监视闭源类和原语的值更改
【发布时间】:2019-07-31 12:19:50
【问题描述】:

我需要能够监控大量对象的变化。几乎在任何情况下,我都可以使用INotifyPropertyChanged 并收工。然而,我的情况并没有那么简单。我的项目的目标是创建一个可以插入、监控和访问任何对象的模拟。

插入是通过使用 Fluent API 的反射完成的,该 API 指定要包含在模拟环境中的属性和字段。它看起来像这样:

public void DeclareVariables( IVariableBuilder builder )
{
  builder.Include( x => x.PropertyA );
  builder.Include( x => x.FieldA );
}

然后将属性和字段包装在 Variable 类中并存储在 Environment 类中。

public class Variable<T> : IVariable
{
  private FieldInfo _field; // Properties are turned into FieldInfo via k__BackingField
  private object _obj;

  public string Id
  {
    get => $"{_obj.GetType}-{_field.Name}";
  }

  public T Value
  {
    get => _field.GetValue( _obj );
  }
}

public class Environment
{
  private Dictionary<string, IVariable> _variables;
}

这会正确存储对我尝试包含的所有字段和属性的引用。 但是,我希望能够监控所有这些更改,并且大多数包含的字段都是闭源类或原语,两者都没有实现 INotifyPropertyChanged` 或无法派生。

我来自 JavaScript 背景,您可以通过创建一个可以覆盖属性 getter 和 setter 的对象代理来完成此操作,并且由于 JavaScript 是鸭子类型的,您只需将实际的对象实例就地替换为代理.

有没有办法在 C# 中做同样的事情?我想 C# 的类型安全规则不允许这样的做法,尤其是对于原语。然而,据我所知,监控这些类的唯一方法是以某种方式拦截正在设置值的操作。

【问题讨论】:

    标签: c# metaprogramming proxy-pattern


    【解决方案1】:

    简而言之,任意对象是不可能的。

    当您在 JavaScript 中执行此操作时,您可以:

    • 就地更改现有对象,例如替换一个特定的成员函数,因为没有修改限制
    • 创建一个新的代理对象

    选项一不能在 C# 中为 arbitrary 对象完成。

    选择选项二,您可以使用具有自定义更改检测逻辑的代理对象包装任意实例。但是,有一些警告:

    1. 为此,所有交互都必须通过代理对象。如果直接修改底层对象,则无法检测到更改。
    2. 代理对象的类型可能与底层的具体类型不兼容。例如,假设您有一个要包装的密封YourCustomClass。代理类,例如YourCustomClassProxy 在 System.Object 之外的层次结构中不共享一个共同的祖先,因此您将无法在方法调用等中将 YourCustomClass 的实例替换为 YourCustomClassProxy 的实例。 因此,虽然有成熟的库用于创建动态代理(参见Castle Project),但它们支持接口和虚拟成员,因为它们可以在运行时被拦截而不会违反类型协定。

    理论上,rewrite IL 可以将您期望的行为添加到封闭的课程中,但我认为它不实用。

    总而言之,可用的策略是:

    • 从没有实现INotifyPropertyChanged 的对象中组合新的(代理)对象,并仅通过代理应用更改
    • 如果上述方法不可行,请查询对象以进行更改。假设您有一个 GUI 应用并且更改是由用户交互引起的,您有时可以预见哪些 GUI 部分会发生更改并强制刷新。

    【讨论】:

      猜你喜欢
      • 2013-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-15
      • 2012-01-13
      • 1970-01-01
      相关资源
      最近更新 更多