Bir değişkenin değeri değiştirildiğinde olay nasıl tetiklenir?


97

Şu anda Visual Studio kullanarak C # 'da bir uygulama oluşturuyorum. Bir değişkenin değeri 1 olduğunda belirli bir kod parçasının yürütülmesi için bir kod oluşturmak istiyorum. Bir if ifadesi kullanabileceğimi biliyorum, ancak sorun, değerin eşzamansız bir süreçte değiştirileceğidir, bu nedenle teknik olarak if ifadesi, değer değişmeden önce göz ardı edilebilir.

Değişken değeri değiştiğinde bir olayın tetiklenmesi için bir olay işleyicisi oluşturmak mümkün müdür? Varsa bunu nasıl yapabilirim?

Bir if ifadesinin nasıl çalıştığını yanlış anlamam tamamen mümkün! Herhangi bir yardım çok takdir edilecektir.


1
Daha açık olmak gerekirse, bir değişkenin değişimini gözlemlemek yalnızca sahip olduğunuz (veya zaten IObservable / INotifyPropertyChanged / Event ile ilgili olan) bir değişken için mümkündür. Gözlemlenmek üzere tasarlanmamışsa, bir sistem değişkeni değişikliğini gözlemleyemezsiniz.
Cœur

Yanıtlar:


125

Bana bir mülk yaratmak istiyormuşsun gibi geliyor.

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

private int _myProperty;

Bu, özellik değeri her değiştiğinde bazı kodlar çalıştırmanıza izin verir. İstersen burada bir etkinlik düzenleyebilirsin.


67

Bir alanın değeri her değiştiğinde bir olay oluşturmak için bir özellik belirleyici kullanabilirsiniz.

Kendi EventHandler temsilcinize sahip olabilir veya ünlü System.EventHandler temsilcisini kullanabilirsiniz.

Genellikle bunun için bir kalıp vardır:

  1. Bir olay işleyici temsilcisiyle (EventArgs türünde bir bağımsız değişkene sahip olan) genel bir olay tanımlayın.
  2. OnXXXXX (örneğin OnMyPropertyValueChanged) adlı korumalı bir sanal yöntem tanımlayın. Bu yöntemde, olay işleyici temsilcisinin boş olup olmadığını kontrol etmelisiniz ve eğer değilse onu çağırabilirsiniz (bu, olay temsilcisine eklenmiş bir veya daha fazla yöntem olduğu anlamına gelir).
  3. Abonelere bir şeyin değiştiğini bildirmek istediğinizde bu korumalı yöntemi arayın.

İşte bir örnek

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();
    }
 }

Bu yaklaşımın avantajı, sınıfınızdan miras almak isteyen diğer sınıfların gerekirse davranışı değiştirmesine izin vermenizdir.

Oluşturulan farklı bir iş parçacığındaki bir olayı yakalamak istiyorsanız, başka bir iş parçacığında tanımlanan nesnelerin durumunu değiştirmemeye dikkat etmelisiniz, bu da çapraz iş parçacığı istisnasının atılmasına neden olur. Bundan kaçınmak için, değişikliğin olayın ortaya çıktığı aynı iş parçacığında gerçekleştiğinden emin olmak için durumunu değiştirmek istediğiniz nesnede bir Invoke yöntemi kullanabilirsiniz veya bir Windows Formuyla uğraşıyorsanız, bir BackgourndWorker kullanarak işleri paralel bir iş parçacığı içinde güzel ve kolay bir şekilde yapabilirsiniz.


3
Web'in tamamındaki en iyi açıklamalardan biri. Sanırım sonunda Özel Olay İşlemeyi anlıyorum. Bu gönderi için teşekkür ederim.

44

.NET çerçevesi aslında bir özellik değiştiğinde aboneleri bilgilendirmek için kullanabileceğiniz bir arabirim sağlar: System.ComponentModel.INotifyPropertyChanged. Bu arayüzde bir PropertyChanged olayı vardır. Genellikle WPF'de bağlama için kullanılır, ancak bunu iş katmanlarında özellik değişikliği bildirimini standartlaştırmanın bir yolu olarak yararlı buldum.

İplik güvenliği açısından, ayarlayıcıya bir kilit koyarım, böylece herhangi bir yarış koşuluna girmezsiniz.

İşte koddaki düşüncelerim :):

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

Umarım bu yardımcı olur :)


6
Diğer cevapların atladığı kilidin dahil edilmesi için +1.
ctacke

1
_Lock nesnesinin kullanımı nedir?
Lode Vlaeminck

2
@LodeVlaeminck, olay işlenirken özelliğin değerinin değiştirilmesini engeller.
David Suarez

IMHO, burası kilitlemek için garip bir yer. [Kilit başka bir yerde kullanılmadıkça, bu farklı bir durumdur.] Paylaşılan bir özelliği ayarlamak için iki farklı iş parçacığı yarış koşulundaysa, özelliğin "son" durumu deterministik değildir. Bunun yerine, bir iş parçacığının özelliğe "sahip olduğu" ve yalnızca onun ayarladığı bir kalıp kullanın. HANGİ model duruma bağlıdır. (Eğer iş parçacıkları arasında gerçekten sahiplik değiştirmek gerekiyorsa, bir baton / jeton geçirin.) Burada bir kilit ihtiyacıyla karşılaşırsam, genel tasarımı dikkatlice incelerim. OTOH, burada bir kilit zararsızdır.
ToolmakerSteve

13

sadece bir mülk kullan

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

1

Basit bir yöntem, değişkende get ve set işlevlerinin kullanılmasını içerir


    using System;
    public string Name{
    get{
     return name;
    }
    
    set{
     name= value;
     OnVarChange?.Invoke();
    }
    }
    private string name;
    
    public event System.Action OnVarChange;


0

genel sınıf kullanabilirsiniz:

class Wrapped<T>  {
    private T _value;

    public Action ValueChanged;

    public T Value
    {
        get => _value;

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

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

ve aşağıdakileri yapabilecektir:

var i = new Wrapped<int>();

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

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

Console.ReadKey();

sonuç:

changed!
changed!
changed!
changed!
changed!
changed!
changed!
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.