방프리

23.05.20 Chapter2. API 설계 (Item 16) 본문

C#/More Effective C#

23.05.20 Chapter2. API 설계 (Item 16)

방프리 2023. 6. 4. 01:11

Item 16 : 상태 전달을 위한 이벤트 패턴을 구현하라

 

이벤트와 델리게이트를 설명할 때 자주 묶지만 둘은 엄연히 다르다.

어떤 타입이 시스템의 변화에 대해서 다수의 클라이언트와 상호작용해야 한다면 이벤트를 활용하는 것이 좋다.

또한 이벤트는 실행 시 멀티 스레드로부터 안전하다.

하단의 코드는 특정 이벤트가 발생 시 로그를 작성하는 클래스이다.

class EventLogger
{
    private static Logger logger = Logger.Singleton;
    private static string eventSource;
    private static EventLog logDest;
    
    static EventLogger() =>
    	logger.Log += (sender, msg) =>
        {
        	logDest?.WriteEntry(msg.Message,
            	EventLogEntryType.Information,
                msg.Priority);
        };
        
    public static string EventSource
    {
    	get { return eventSource; }
        set
        {
        	eventSource = value;
            if (EventLog.SourceExists(eventSource) == false)
            {
            	EventLog.CreateEventSource(eventSource,
                	"ApplicationEventLogger");
            }
            
            logDest?.Dispose();
            logDest = new EventLog();
            logDest.Source = eventSource;
        }
    }
}

위의 클래스의 단점은 하나의 이벤트 시스템에 수많은 이벤트가 등록될 수 있다는 점이다.

.Net Framework에서는 런타임에도 이벤트 등록 및 삭제를 컨트롤할 수 있지만 특정 상황에 사용할 수 있는 이벤트들의

핸들러를 저장하는 편이 더 좋다.

public sealed class Logger
{
    private static Dictionary<string,
    	EventHandler<LoggerEventArgs>>
        	Handlers = new Dictionary<string, EventHandler<LoggerEventArgs>>();
            
    static public void AddLogger(
    	string system, EventHandler<LoggerEventArgs> ev)
    {
    	if (Handlers.ContainsKey(system))
        {
        	Handlers[system] += ev;
        }
        else
        {
        	Handlers.Add(system, ev);
        }
    }
    
    static public void RemoveLogger(string system,
    	EventHandler<LoggerEventArgs> ev) => Handlers[system] -= ev;
        
    static public void AddMsg(string system, int priority, string msg)
    {
    	if (string.IsNullOrEmpty(system))
        {
        	EventHandler<LoggerEventArgs> handler = null;
            Handlers.TryGetValue(system, out l);
            
            LoggerEventArgs args = new LoggerEventArgs(priority, msg);
            handler?.Invoke(null, args);
            
            handler = Handlers[""] as EventHandler<LoggerEventArgs>;
            handler?.Invoke(null, args);
        }
    }
}
Comments