大家好!
我正在尝试一些日志记录功能,特别是使用内插字符串添加调用者信息进行日志记录。这是在Visual Studio 2022中使用c# &net 6.0 .
我正在尝试将调用者信息(名称,路径和行号)添加到方法:
public static void Log<T>(this T logLabel, [InterpolatedStringHandlerArgument("logLabel")] TraceLoggerParamsInterpolatedStringHandler handler)
where T : Enum
{
...
}
问题在于调用者信息需要在将这些参数的处理程序发送给TraceLoggerParamsInterpolatedStringHandler本身的构造函数之前出现。然而,由于这些属性要求这些参数具有默认值,这意味着处理程序也需要一个默认值。
如果我这样做:
public static void Log<T>(this T logLabel,
[CallerMemberName] string callerName = "",
[CallerFilePath] string callerFilePath = "",
[CallerLineNumber] int callerLineNumber = -1,
[InterpolatedStringHandlerArgument("logLabel", "callerName", "callerFilePath", "callerLineNumber")] TraceLoggerParamsInterpolatedStringHandler handler = default)
where T : Enum
{
...
}
然后将处理程序初始化为默认值,它不调用接受附加参数的专用构造函数。我不知道这是否是一个代码生成问题,在这种情况下插入字符串。
呼叫站点:
00007FF84DD2B2AF call Method stub for: System.Runtime.CompilerServices.DefaultInterpolatedStringHandler..ctor(Int32, Int32) (07FF84D6AC1B0h)
00007FF84DD2B2B4 mov rdx,260C53C4D68h
00007FF84DD2B2BE mov rdx,qword ptr [rdx]
00007FF84DD2B2C1 lea rcx,[rbp+0A8h]
00007FF84DD2B2C8 call Method stub for: System.Runtime.CompilerServices.DefaultInterpolatedStringHandler.AppendLiteral(System.String) (07FF84D6AC1F8h)
我怀疑,然而,我只需要移动这些参数,并将它们显式地传递给处理程序来解决这个问题。
如果有更优雅的解决方案,我将非常感谢!
谢谢你,布伦特Scriver
事实证明这很简单:只需将各种[Caller...]
参数添加到InterpolatedStringHandler
构造函数本身。这样的:
[InterpolatedStringHandler]
public readonly ref struct LogInterpolatedStringHandler
{
private readonly StringBuilder _builder;
public LogInterpolatedStringHandler(int literalLength, int formattedCount,
[CallerFilePath] string filePath = "",
[CallerLineNumber] int lineNumber = 0)
{
_builder = new StringBuilder(literalLength);
_builder.Append(filePath);
_builder.Append(':');
_builder.Append(lineNumber);
}
public void AppendLiteral(string s)
{
_builder.Append(s);
}
public void AppendFormatted<T>(T t)
{
_builder.Append(t);
}
internal string GetFormattedText() => _builder.ToString();
}
那么,你根本不需要[InterpolatedStringHandlerArguments]
。你的方法签名可以是:
static void Log(LogInterpolatedStringHandler handler)
{
Console.WriteLine(handler.GetFormattedText());
}
按预期调用:
static void Main(string[] args)
{
string s = "Hello World";
int i = 50;
Log($"string is {s}, int is {i}");
}
编译器,正确地,把它变成这样:
private static void Main(string[] args)
{
string s = "Hello World";
int i = 50;
LogInterpolatedStringHandler handler = new LogInterpolatedStringHandler(19, 2, "<full path here>\Program.cs", 87);
handler.AppendLiteral("string is ");
handler.AppendFormatted(s);
handler.AppendLiteral(", int is ");
handler.AppendFormatted(i);
Log(handler);
}
并且,顺便说一下,这仍然会工作,如果你实际上必须使用[InterpolatedStringHandlerArgument]与额外的参数。