Combining CallerMemberName with params

本文关键字:params with CallerMemberName Combining | 更新日期: 2023-09-27 17:53:44

现在(c# 4.0),我们的日志记录方法看起来像

public void Log(string methodName, string messageFormat, params object[] messageParameters)

,其中记录器进行字符串格式化,以便调用者不必放置string。格式来创建一个漂亮的日志消息(如果没有附加日志查看器,则允许记录器跳过字符串格式化)。

在c# 5.0中,我想通过使用新的CallerMemberName属性来摆脱methodName参数,但我不知道如何将其与'params'关键字结合起来。有办法做到这一点吗?

Combining CallerMemberName with params

你可以这样做:

protected static object[] Args(params object[] args)
{
    return args;
}
protected void Log(string message, object[] args = null, [CallerMemberName] string method = "")
{
    // Log
}

要使用日志,这样做:

Log("My formatted message a1 = {0}, a2 = {2}", Args(10, "Nice"));

我相信您根本无法将paramsCallerMemberName所需的可选参数结合起来。你能做的最好的是使用实际的数组而不是params

要构建@guilhermekmelo的答案,我可能建议使用链式方法:

所以保持当前的Log(string,string,object[]方法:

public void Log(string methodName, string messageFormat, params object[] messageParameters)

并添加这个新的重载(Log(string,string)):

public LogMessageBuilder Log(string messageFormat, [CallerMemberName] string methodName = null)
{
    // Where `this.Log` is 
    return new LogMessageBuilder( format: messageFormat, logAction: this.Log );
}
public struct LogMessageBuilder
{
    private readonly String format;
    private readonly String callerName;
    private readonly Action<String,String,Object[]> logAction;
    public LogMessageBuilder( String format, String callerName, Action<String,String,Object[]> logAction )
    {
        this.format = format;
        this.callerName = callerName;
        this.logAction = logAction;
    }
    public void Values( params Object[] values )
    {
        this.logAction( this.format, this.callerName, values );
    }
}

像这样使用:

this.Log( "My formatted message a1 = {0}, a2 = {2}" ).Values( 10, "Nice" );

注意LogMessageBuilder是一个struct,所以它是一个值类型,这意味着它不会引起另一个GC分配——尽管使用params Object[]会在调用站点引起数组分配。(我希望c#和。net支持基于堆栈的可变参数,而不是用堆分配的参数数组伪造它)。


另一种选择是使用FormattableString -但请注意,由于c#编译器为FormattableString内置了特殊情况魔法,您需要小心不要让它隐式地转换为String(也很糟糕,您不能直接向FormattableString添加扩展方法,抱怨):

public void Log(FormattableString fs, [CallerMemberName] string methodName = null)
{
    
    this.Log( messageFormat: fs.Format, methodName: methodName, messageParameters: fs.GetArguments() );
}

用法:

this.Log( $"My formatted message a1 = {10}, a2 = {"Nice"}" );