在物业上发射一个事件/功能? (C#)

时间:2009-08-06 10:40:23

标签: c# .net custom-event

我正在使用一个我无法编辑的类,它有一个属性(一个布尔值),当它发生变化时会被告知它很好,我无法编辑属性获取或设置为我导入类来自.dll(我没有代码)。

如何创建在更改属性时触发的事件/函数?

其他
它只在自己的类中更改,直接更改为底层的私有变量。

E.g。

private bool m_MyValue = false;

public bool MyValue
  {
  get { return m_MyValue; }
  }

private void SomeFunction()
  {
  m_MyValue = true;
  }

8 个答案:

答案 0 :(得分:10)

你不能,基本上......不是没有使用类似调试器API的东西在执行时注入代码并修改原始库的IL(我不推荐其中任何一个解决方案;除了其他任何东西它可能违反了图书馆的许可证。)

基本上,如果某个属性不支持通知,则它不支持通知。您应该寻找一种不同的方法来解决您的问题。 (举例来说,民意调查会有效吗?)

答案 1 :(得分:5)

你不能直接这样做[正如Jon Skeet所说],除非它是虚拟的,否则你可以拦截班级的所有实例创作,并且对支持领域没有任何影响,影响真正的'价值'该项目。

强行执行此操作的唯一方法是使用Mono.Cecil或MS CCI来检测道具设定器la this DimeCast on Cecil。 (或PostSharp)

然而,这不会捕获对支持字段的内部更改(如果有的话)。 (这就是包装可能不起作用的原因)。

更新:鉴于您的更新,您肯定试图捕获基础字段更改,唯一的方法是使用PS / CCI / Cecil并分析流程以拦截所有字段更新。总之,不太可行。

答案 2 :(得分:3)

可以说,唯一真正的方法是创建某种“观察者”组件,在一个单独的线程中运行,其作用是每隔一段时间读取一次属性,并在属性值发生变化时引发一个事件。当然,这种解决方案在线程和同步的浑水中航行。

假设您的应用程序是针对此对象的单线程,您最干净的解决方案是通过代理对象对此对象进行方法调用。它可以检查属性的前后状态,并在事件发生变化时引发事件。

这是我正在谈论的一个简单例子:

public class SomeProxy
{
    public SomeProxy(ExternalObject obj)
    {
         _obj = obj;
    }

    public event EventArgs PropertyChanged;

    private bool _lastValue;

    private ExternalObject _obj;

    protected virtual void OnPropertyChanged()
    {
        if(PropertyChanged != null)
            PropertyChanged();
    }

    protected virtual void PreMethodCall()
    {
        _lastValue = _obj.SomeProperty;
    }

    protected virtual void PostMethodCall()
    {
        if(_lastValue != _obj.SomeProperty)
            OnPropertyChanged();
    }

    // Proxy method.
    public SomeMethod(int arg)
    {
        PreMethodCall();
        _obj.SomeMethod(arg); // Call actual method.
        PostMethodCall();
    }
}

显然,你可以将这个代理模式构建到一个合适的对象中 - 你只需要知道所有调用必须通过代理才能在你预期的时候引发事件。

答案 3 :(得分:2)

如前所述,最直接的方法(以及需要对代码进行最少更改的方法)是使用AOP库,如PostSharp。

然而,使用传统的C#/ .NET可以通过使用dependency property pattern来实现解决方案,通过WPF使用效果很好。我建议您阅读此内容,并考虑为您的项目实施这样一个系统(或至少是它的简化版本),如果合适的话。

答案 4 :(得分:1)

你需要在setter属性中创建一个包装类的类,在setter属性中使用普通方法在那里引发一个事件。

答案 5 :(得分:1)

你可以从班级继承并隐藏属性吗?像这样......

class MyClass : BaseClass
{
    // hide base property.
    public new bool MyProperty
    {
        get
        {
            return base.MyProperty;
        }

        set
        {
            base.MyProperty = value;
            RaiseMyPropertyChangedEvent();
        }
    }
}

答案 6 :(得分:0)

我认为Alex对包装器的想法很好,但是,鉴于对您来说最重要的是您知道在使用之前更改了值,您只需将通知移至吸气剂,避免内部价值变化的担忧。这样你就可以获得类似于轮询的东西,但是可靠:

class MyClass : BaseClass
{
    //local value
    private bool local;

    //first access yet?
    private bool accessed = false;

    // Override base property.
    public new bool MyProperty
    {
        get
        {
            if(!accessed)
            {
                // modify first-get case according to your taste, e.g.
                local = base.MyProperty;
                accessed = true;
                RaiseMyPropertyChangedBeforeUseEvent();
            }
            else
            {
                if(local != base.MyProperty)
                {
                    local = base.MyProperty;
                    RaiseMyPropertyChangedBeforeUseEvent();
                }
            }

            return local;
        }

        set
        {
            base.MyProperty = value;
        }
    }
}

答案 7 :(得分:-1)

您可以尝试继承它并使用它的孩子而不是它。 覆盖属性的“set”,以便引发事件。

编辑:...仅当属性在父类中是虚拟的时才...