将动态对象传递给 .NET 6 中的自定义内插字符串处理程序时出现无效实例化异常

Row*_*ish 6 c# string-interpolation .net-6.0 c#-10.0

我在我的记录器方法中发现升级到 .NET 6 时出现问题LogErrorInterpolatedStringHandler

这是经典的方法:

public static void Log(string message, params object[] pars)
{
    // Log message
}
Run Code Online (Sandbox Code Playgroud)

这是升级后的:

public static void Log(ref LogErrorInterpolatedStringHandler message, params object[] pars)
{
    // Log message
}
Run Code Online (Sandbox Code Playgroud)

我升级了该方法,以获得此处描述的 C# 10 和 .NET 6 的性能改进。

该方法的新版本运行良好,除非dynamic在插值字符串中传递对象时。

这是一个例子:

// Works well   
Logger.Log($"Log: {stringOrEverythingElseObject}");

// Exception
Logger.Log($"Log: {dynamicObject}");
Run Code Online (Sandbox Code Playgroud)

抛出的异常是

通用类型“<>A{00000004}`3”在程序集“MyAssembly,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”中使用了无效实例化。

我发现了一个与我的问题类似的拉取请求,但无法理解如何在我的代码中修复。

你有什么主意吗?谢谢!

Gur*_*ron 5

长话短说

除了在调用站点dynamicObject进行转换之外,您无能为力:object

Logger.Log($"Log: {(object)dynamicObject}");
Run Code Online (Sandbox Code Playgroud)

ref或从处理程序中删除:

[InterpolatedStringHandler]
public struct LogErrorInterpolatedStringHandler
Run Code Online (Sandbox Code Playgroud)

但不确定它会如何影响性能(尽管使用dynamic对性能的影响应该比这大得多,一般来说你应该避免dynamic在性能敏感的代码中)

尝试解释

ref structdynamic由于以下限制, s 不能很好地工作:

  • 结构体ref不能是类型参数。

处理代码时dynamic使用相关类型作为类型参数。即如下代码:

Logger.Log($"Log: {(object)dynamicObject}");
Run Code Online (Sandbox Code Playgroud)

将导致编译器生成类似的结果:

private static class <>o__0
{
    public static CallSite<<>A{00000002}<CallSite, Handler, object>> <>p__0;
}
Run Code Online (Sandbox Code Playgroud)

请注意Handler类型参数列表中的 ,这将导致完全相同的运行时错误。ref从处理程序中删除可以解决该问题。

正如本测试中的注释和Stephen Toub 的注释中所指出的,当前 Roslyn 在运行时失败时不会为此代码发出任何构建时错误。