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

Invalid instantiation exception when pass dynamic object to custom interpolated string handler in .NET 6

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

这里是经典方法:

public static void Log(string message, params object[] pars)
{
    // Log message
}

这是升级版:

public static void Log(ref LogErrorInterpolatedStringHandler message, params object[] pars)
{
    // Log message
}

我升级了方法以获得 C# 10 和 .NET 6 所述的性能改进 here

除了在内插字符串中传递 dynamic 对象外,新版本的方法运行良好。

这是一个例子:

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

// Exception
Logger.Log($"Log: {dynamicObject}");

抛出的异常是

The generic type '<>A{00000004}`3' was used with an invalid instantiation in assembly 'MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

我发现 a pull request 与我的问题类似,但无法理解如何在我的代码中修复。

你有什么想法吗? 谢谢!

TL;DR

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

Logger.Log($"Log: {(object)dynamicObject}");

或从处理程序中删除 ref

[InterpolatedStringHandler]
public struct LogErrorInterpolatedStringHandler

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

尝试解释

由于 following limitation:

ref struct 不能很好地与 dynamic 一起使用

  • A ref struct can't be a type argument.

虽然处理 dynamic 的代码使用相关类型作为类型参数。 IE。以下代码:

var handler = new Handler();
handler.AppendFormatted((dynamic)5);

ref struct Handler
{
    // or public void AppendFormatted<T>(T value) { }
    public void AppendFormatted(object value) { }
}

会产生这样的结果 generated by compiler:

private static class <>o__0
{
    public static CallSite<<>A{00000002}<CallSite, Handler, object>> <>p__0;
}

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

如本 test comments and this comment by Stephen Toub 中所述,当前 Roslyn 在运行时失败时不会为此代码发出任何构建时错误。