当变量的值发生变化时如何触发事件?

我目前正在使用 Visual Studio 在 C # 中创建一个应用程序。我想创建一些代码,这样当一个变量的值为1时,就可以执行某段代码。 I know that I can use an if statement but the problem is that the value will be changed in an asynchronous process so technically the if statement could be ignored before the value has changed.

是否可以创建一个事件处理程序,以便在变量值更改时触发事件?如果是这样,我该怎么做?

我完全有可能误解了 if 语句的工作原理! 如果您能提供任何帮助,我将不胜感激。

246009 次浏览

在我看来,你想创造一个财产。

public int MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
if (_myProperty == 1)
{
// DO SOMETHING HERE
}
}
}


private int _myProperty;

这允许您在属性值更改时运行一些代码。如果你愿意,你可以在这里举办活动。

只要使用属性

int  _theVariable;
public int TheVariable{
get{return _theVariable;}
set{
_theVariable = value;
if ( _theVariable == 1){
//Do stuff here.
}
}
}

每当字段的值要更改时,可以使用属性设置器引发事件。

您可以拥有自己的 EventHandler 委托,也可以使用著名的 System.EventHandler 委托。

通常这种情况都有一个模式:

  1. Define a public event with an event handler delegate (that has an argument of type EventArgs).
  2. 定义一个名为 OnXXXXX 的受保护虚拟方法(例如 OnMyPropertyValueChanged)。在此方法中,您应该检查事件处理程序委托是否为 null,如果不是,则可以调用它(这意味着有一个或多个方法附加到事件委托)。
  3. 无论何时您想通知订阅者某些事情已经改变,都可以调用这个受保护的方法。

Here's an example

private int _age;


//#1
public event System.EventHandler AgeChanged;


//#2
protected virtual void OnAgeChanged()
{
if (AgeChanged != null) AgeChanged(this,EventArgs.Empty);
}


public int Age
{
get
{
return _age;
}


set
{
//#3
_age=value;
OnAgeChanged();
}
}

这种方法的优点是,如果需要,可以让任何其他希望从类继承的类更改行为。

如果你想在另一个线程中捕获一个正在引发的事件,你必须小心不要改变在另一个线程中定义的对象的状态,这会导致一个跨线程异常被抛出。为了避免这种情况,你可以使用 Invoke 方法来改变对象的状态,以确保改变发生在引发事件的同一个线程中,或者在处理 Windows 窗体时,你可以使用 BackgorndWorker 在一个并行线程中轻松地完成工作。

那个。NET 框架实际上提供了一个接口,可用于在属性更改时通知订阅方: System。组件模型。此接口有一个 PropertyChanged 事件。它通常在 WPF 中用于绑定,但我发现它在业务层中作为标准化属性更改通知的方法很有用。

在线程安全方面,我会在 setter 中设置一个锁,这样就不会遇到任何竞态条件。

Here are my thoughts in code :) :

public class MyClass : INotifyPropertyChanged
{
private object _lock;


public int MyProperty
{
get
{
return _myProperty;
}
set
{
lock(_lock)
{
//The property changed event will get fired whenever
//the value changes. The subscriber will do work if the value is
//1. This way you can keep your business logic outside of the setter
if(value != _myProperty)
{
_myProperty = value;
NotifyPropertyChanged("MyProperty");
}
}
}
}


private NotifyPropertyChanged(string propertyName)
{
//Raise PropertyChanged event
}
public event PropertyChangedEventHandler PropertyChanged;
}




public class MySubscriber
{
private MyClass _myClass;


void PropertyChangedInMyClass(object sender, PropertyChangedEventArgs e)
{
switch(e.PropertyName)
{
case "MyProperty":
DoWorkOnMyProperty(_myClass.MyProperty);
break;
}
}


void DoWorkOnMyProperty(int newValue)
{
if(newValue == 1)
{
//DO WORK HERE
}
}
}

Hope this is helpful :)

二零二二年

you can use generic class:

class Wrapped<T>  {
private T _value;


public Action WillChange;
public Action DidChange;


public T Value
{
get => _value;


set
{
if ( _value != value )
{
OnWillChange();
_value = value;
OnDidChanged();
}
}
}


protected virtual void OnWillChange() => WillChange?.Invoke();
protected virtual void OnDidChange() => DidChange?.Invoke();
}

并将能够做到以下几点:

var i = new Wrapped<int>();


i.WillChange += () => { Console.WriteLine("will be changed!"); };
i.DidChange += () => { Console.WriteLine("changed!"); };


i.Value = 10;
i.Value = 11;
i.Value = 10;
i.Value = 11;


Console.ReadKey();

结果:

will be changed!
changed!
will be changed!
changed!
will be changed!
changed!
will be changed!
changed!

一个简单的方法包括对变量使用 get 和 set 函数


using System;
public string Name{
get{
return name;
}
    

set{
name= value;
OnVarChange?.Invoke();
}
}
private string name;
    

public event System.Action OnVarChange;