2018/01/05

C# 이벤트 발생

이벤트를 발생하는 방법.

속성의 값이 변경되면 이벤트를 발생하고 처리를 해보자.

event 키워드를 사용하여 이벤트를 선언 하고
이벤트 대리자를(핸들러 메서드 형식) 지정 한다.

public event EventHandler ValueChanged;

대리자는 반환값이 없고(void) 이벤트 발생 객체 와 이벤트 데이터를 인자로 한다.

public delegate void EventHandler(object sender, EventArgs e);

이 형식을 무시해도 되지만 MS 가이드를 따르도록 한다.
이벤트 핸들러가 void가 아니면 의미도 이상하다.

다음은 이벤트 선언과 발생의 코드 이다.

class Item
{
    public event EventHandler ValueChanged;

    private int value;
    public int Value
    {
        get => this.value;

        set
        {
            if (this.value != value)
            {
                this.value = value;
                OnValueChanged(EventArgs.Empty);
            }
        }
    }

    protected virtual void OnValueChanged(EventArgs e)
    {
        this.ValueChanged?.Invoke(this, e);
    }
}

속성 값 Value의 값이 변경 되었을때 이벤트를 발생한다.
Null 조건 연산자를 사용하여 스레드로부터 안전한방식으로 대리자를 호출한다.

상속을 고려하지 않는다면 OnValueChanged 메서드를 전용(private) 으로 작성해도 무관하다.

다음은 이벤트처리 코드 이다.

Item item = new Item();

item.ValueChanged += (s, e) => 
{
    Console.WriteLine($"new value: {item.Value}");
};

item.Value = 10;

다음은 조금 수정하여 이벤트 데이터를 사용하여 변경전값과 현재값을 전달한다.

이벤트 데이터 정의:

class ValueChangedEventArgs : EventArgs
{
    public int OldValue { get; }
    public int NewValue { get; }

    public ValueChangedEventArgs(int oldValue, int newValue)
    {
        this.OldValue = oldValue;
        this.NewValue = newValue;
    }        
}

이벤트 데이터 사용:

class Item
{
    public event EventHandler<ValueChangedEventArgs> ValueChanged;

    private int value;
    public int Value
    {
        get => this.value;

        set
        {
            if (this.value != value)
            {
                var oldValue = this.value;
                this.value = value;
                OnValueChanged(new ValueChangedEventArgs(oldValue, this.value));
            }
        }
    }

    protected virtual void OnValueChanged(ValueChangedEventArgs e)
    {
        this.ValueChanged?.Invoke(this, e);
    }
}

이벤트 핸들러에서 데이터 사용:

Item item = new Item();

item.ValueChanged += (s, e) =>
{
    Console.WriteLine($"old value: {e.OldValue}, new value: {e.NewValue}");
};

item.Value = 10;

이번에는 여러 속성에서 사용 할 수 있도록 변경 한다.
속성명을 알아내기 위해 CallerMemberName Attribute 를 사용 했다.

수정된 전체 코드:

class PropertyValueChangedEventArgs : EventArgs
{
    public string PropertyName { get; }
    public object OldValue { get; }
    public object NewValue { get; }

    public PropertyValueChangedEventArgs(string propertyName, object oldValue, object newValue)
    {
        this.PropertyName = propertyName;
        this.OldValue = oldValue;
        this.NewValue = newValue;
    }
}

class Item
{
    public event EventHandler<PropertyValueChangedEventArgs> PropertyValueChanged;

    private int intValue;
    public int IntValue
    {
        get => this.intValue;

        set
        {
            if (this.intValue != value)
            {
                var oldValue = this.intValue;
                this.intValue = value;
                OnPropertyValueChanged(oldValue, this.intValue);
            }
        }
    }

    private string strValue;
    public string StrValue
    {
        get => this.strValue;

        set
        {
            if (this.strValue != value)
            {
                var oldValue = this.strValue;
                this.strValue = value;
                OnPropertyValueChanged(oldValue, this.strValue);
            }
        }
    }

    private void OnPropertyValueChanged(            
        object oldValue, object newValue,
        [CallerMemberName] string memberName = "")
    {
        this.PropertyValueChanged?.Invoke(this, new PropertyValueChangedEventArgs(memberName, oldValue, newValue));
    }
}

class Program
{
    static void Main(string[] args)
    {
        Item item = new Item();

        item.PropertyValueChanged += (s, e) =>
        {
            Console.WriteLine($"property name: {e.PropertyName} old value: {e.OldValue}, new value: {e.NewValue}");
        };

        item.IntValue = 10;
    }
}

C# 문자열 포함 여부 확인하기.

ToUpper() 를 사용하면 불필요한 문자열을 생성하므로 좋은 방법은 아니다. string text = "This is an apple." ; string apple = "Apple." ; bool ...