c# - 在 C# 中使用动态绑定(bind)代替严格类型值的扩展方法

标签 c# .net .net-core compilation

我有一个返回 int 值的短表达式,我正在尝试对结果值调用扩展方法,但是当内部表达式中存在任何动态变量时,将使用动态联编程序并且我收到异常Microsoft.CSharp.RuntimeBinder.RuntimeBinderException 消息为

'int' does not contain a definition for 'AsStringOrNull'

以下是重现该问题的所有代码:

using System;

namespace ExtensionMethodsAndDynamic
{

    static class Extensions
    {
        public static string AsStringOrNull(this object value) => value?.ToString();
    }

    class Program
    {
        public static object Foo(object value) => value;
        static int GetIntFrom(object anything) => 1;


        static void Main()
        {
            dynamic dynamicVariable = null;

            string result1 = GetIntFrom((object)dynamicVariable).AsStringOrNull();// Works as expected
            string result2 = GetIntFrom(dynamicVariable).AsStringOrNull();        
            string result3 = GetIntFrom(Foo(dynamicVariable)).AsStringOrNull();   
        }
    }
}

另外,我注意到另一个我无法理解的行为。
The function is successfully called with a strictly typed argument
The same doesn't work for a dynamic argument
But it will work if we specify the function

请帮助我理解为什么与动态变量相关的内容会传播到此函数 int GetIntFrom(object anything) 的调用之外。

最佳答案

扩展方法在编译时进行评估,并替换为适当的静态调用。但是当您使用 dynamic 时,调用会在运行时解析。这意味着当您在动态变量后键入“AsStringOrNull”时,您所做的事情与在静态类型变量后键入它时完全不同。

编译器完成工作后,实际执行的代码有点像这样:

static class Extensions
{
    // Note the absent "this" keyword. It's just an ordinary method after compilation
    public static string AsStringOrNull(object value) => value?.ToString();
}

class Program
{
    public static object Foo(object value) => value;
    static int GetIntFrom(object anything) => 1;


    static void Main()
    {
        dynamic dynamicVariable = null;

        string result1 = Extensions.AsStringOrNull(GetIntFrom((object)dynamicVariable));

        object intObj = GetIntFrom(dynamicVariable); // this step is actually much more complicated
        string result2 = intObj.GetType().GetMethod("AsStringOrNull")?.Invoke(intObj) ?? throw new RuntimeBinderException();
    }
}

为了简洁起见,我不会列出 result3 会发生什么。上面应该已经说清楚了为什么会抛出异常。当方法解析中涉及任何动态变量时,您就不能使用静态编译器糖。

IDE 不会在这里生成任何错误,因为动态对象出于显而易见的原因根本不检查错误。但是,如果您尝试在第二次和第三次调用“AsStringOrNull”时使用 Go To Reference/F12,您应该会看到它们没有被解析。

关于c# - 在 C# 中使用动态绑定(bind)代替严格类型值的扩展方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64292891/

相关文章:

c# - Visual Studio 2013 - Entity Framework - 更新向导没有响应

c# - 使用 LINQ 获取表中的位置

c# - 在页面加载时将焦点设置在文本框上

c# - 为额外信息创建通用类成员

c# - 我应该如何以合理的方式管理工具栏、菜单和上下文相关元素?

c# - 运算符 == 是如何选择的?

c# - 通过 AzureServiceTokenProvider 对 CloudTableClient 进行 Azure 存储身份验证

c# - 无法从 ViewComponent 中解析缓存服务

c# - 为什么我的 NLog 配置不能在我的服务器机器上运行?

json - 如何在 nuget 包中包含 appsettings.json 配置设置?