返回语句后的C#fire事件

时间:2018-02-25 14:30:20

标签: c# asp.net

我有Log方法创建LogMessage对象,并触发事件OnMessage

该方法在调用LogMessage后返回event对象。

是否可以延迟事件,因此它发生在return语句之后?

我需要这个的原因是因为我希望能够在事件发生之前改变LogMessage对象。

public class Logger
{
    public static event LogMessageCreatedEventHandler OnMessage;

    public LogMessage Log(string logLevel, string message)
    {
        LogMessage logMessage = new LogMessage
        {
            Message = message,
            LogLevel = logLevel,
            DateTime = DateTime.UtcNow
        };

        OnMessage?.Invoke(this, new LogMessageCreatedEventArgs { LogMessage = logMessage });

        return logMessage;
    }
}


// usage

var logMessage = _logger.Log("Debug", "Product has been created");  <-- the event is invoked now
logMessage.CustomProp.Add("isProductsService", true);               <-- this property is not available in the Event Handler

一个想法是使用Task.Delay(),但我不认为这是一个很好的解决方案。

Task.Delay(1000).ContinueWith(_ => {
    OnMessage?.Invoke(this, new LogMessageCreatedEventArgs { LogMessage = logMessage });
});

return message;

1 个答案:

答案 0 :(得分:4)

使用Task.Delay(1000)会产生竞争条件。将事件延迟到return不足之后,因为调用者可能有或没有足够的时间及时完成对LogMessage的修改,以便事件获取修改后的属性。

确保在触发事件之前修改已结束的一种方法是在创建事件和触发事件之间插入一段代码。这可以通过代表来完成:

public static event LogMessageCreatedEventHandler OnMessage;
// By default message preprocessor does nothing
public static Func<LogMessage,LogMessage> Preprocess { get; set; } = m => m;

public LogMessage Log(string logLevel, string message) {
    LogMessage logMessage = new LogMessage {
        Message = message,
        LogLevel = logLevel,
        DateTime = DateTime.UtcNow
    };
    OnMessage?.Invoke(this, new LogMessageCreatedEventArgs {
        LogMessage = Preprocess(logMessage)
    });
    return logMessage;
}

现在您可以将预处理逻辑添加到Logger以修改LogMessage

Logger.Preprocessor = lm => {
    lm.PropertyToBeChanged = newPropertyValue;
    lm.AnotherProperty = someOtherValue;
    return lm;
};
  

我需要更新&#34; contextual&#34;等级,而不是全局级别,我丢失了创建日志消息的信息。

您可以将Func作为参数传递给Log,如下所示:

private static readonly Func<LogMessage,LogMessage> doNothing = m => m;
public LogMessage Log(string logLevel, string message, Func<LogMessage,LogMessage> preprocess = doNothing) {
    LogMessage logMessage = new LogMessage {
        Message = message,
        LogLevel = logLevel,
        DateTime = DateTime.UtcNow
    };
    OnMessage?.Invoke(this, new LogMessageCreatedEventArgs {
        LogMessage = preprocess(logMessage)
    });
    return logMessage;
}