为了建立@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
是 a 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"}" );