我正在使用一个我无法编辑的类,它有一个属性(一个布尔值),当它发生变化时会被告知它很好,我无法编辑属性获取或设置为我导入类来自.dll(我没有代码)。
如何创建在更改属性时触发的事件/函数?
其他
它只在自己的类中更改,直接更改为底层的私有变量。
E.g。
private bool m_MyValue = false;
public bool MyValue
{
get { return m_MyValue; }
}
private void SomeFunction()
{
m_MyValue = true;
}
答案 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”,以便引发事件。
编辑:...仅当属性在父类中是虚拟的时才...