如何将interpolatedstringhandlerargument与CallerMemberName、Caller



大家好!

我正在尝试一些日志记录功能,特别是使用内插字符串添加调用者信息进行日志记录。这是在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]与额外的参数。

相关内容

  • 没有找到相关文章

最新更新