[c#] 변수 값이 변경 될 때 이벤트를 트리거하는 방법은 무엇입니까?

현재 Visual Studio를 사용하여 C #으로 응용 프로그램을 만들고 있습니다. 변수의 값이 1 일 때 특정 코드가 수행되도록 코드를 만들고 싶습니다. if 문을 사용할 수 있지만 문제는 비동기 프로세스에서 값이 변경되므로 값이 변경되기 전에 기술적으로 if 문을 무시할 수 있다는 것입니다.

변수 값이 변경 될 때 이벤트가 트리거되도록 이벤트 핸들러를 만들 수 있습니까? 그렇다면 어떻게해야합니까?

if 문이 어떻게 작동하는지 오해했을 가능성이 있습니다! 어떤 도움이라도 대단히 감사하겠습니다.



답변

당신이 속성을 만들고 싶어하는 것 같습니다.

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

private int _myProperty;

이렇게하면 속성 값이 변경 될 때마다 일부 코드를 실행할 수 있습니다. 원한다면 여기서 이벤트를 제기 할 수 있습니다.


답변

필드 값이 변경 될 때마다 속성 설정기를 사용하여 이벤트를 발생시킬 수 있습니다.

고유 한 EventHandler 대리자를 가질 수도 있고 유명한 System.EventHandler 대리자를 사용할 수도 있습니다.

일반적으로 이에 대한 패턴이 있습니다.

  1. EventArgs 유형의 인수가있는 이벤트 처리기 대리자를 사용하여 공용 이벤트를 정의합니다.
  2. OnXXXXX (예 : OnMyPropertyValueChanged)라는 보호 된 가상 메서드를 정의합니다. 이 메서드에서 이벤트 처리기 대리자가 null인지, 그렇지 않은 경우이를 호출 할 수 있는지 확인해야합니다 (이벤트 위임에 연결된 메서드가 하나 이상 있음을 의미 함).
  3. 구독자에게 변경 사항을 알리고 싶을 때마다이 보호 된 메서드를 호출하십시오.

여기에 예가 있습니다.

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 Form을 처리하는 경우 BackgourndWorker를 사용하여 병렬 스레드에서 쉽고 편리하게 작업 할 수 있습니다.


답변

.NET 프레임 워크는 속성이 변경된 경우 구독자에게 알리는 데 사용할 수있는 인터페이스 인 System.ComponentModel.INotifyPropertyChanged를 실제로 제공합니다. 이 인터페이스에는 PropertyChanged 이벤트가 하나 있습니다. 일반적으로 바인딩을 위해 WPF에서 사용되지만 속성 변경 알림을 표준화하는 방법으로 비즈니스 계층에서 유용하다는 것을 알았습니다.

스레드 안전성 측면에서 나는 당신이 어떤 경쟁 조건에 부딪치지 않도록 setter에 잠금을 둘 것입니다.

코드에 대한 내 생각은 다음과 같습니다.

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
        }
    }
}

이것이 도움이 되었기를 바랍니다 🙂


답변

그냥 속성을 사용

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


답변

일반 클래스를 사용할 수 있습니다.

class Wrapped<T>  {
    private T _value;

    public Action ValueChanged;

    public T Value
    {
        get => _value;

        set
        {
            OnValueChanged();
            _value = value;
        }
    }

    protected virtual void OnValueChanged() => ValueChanged?.Invoke() ;
}

다음을 수행 할 수 있습니다.

var i = new Wrapped<int>();

i.ValueChanged += () => { Console.WriteLine("changed!"); };

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

Console.ReadKey();

결과:

changed!
changed!
changed!
changed!
changed!
changed!
changed!


답변