要以@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 - 但请注意,由于FormattableString 的 C# compiler has built-in special-case magic 您需要小心不要让它被隐式转换为 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"}" );