【问题标题】:Method overload resolution using dynamic argument使用动态参数的方法重载解析
【发布时间】:2011-08-26 20:07:29
【问题描述】:

这可能以前已经回答过了。我看到许多“动态方法重载解析”问题,但没有一个专门处理传递 dynamic 参数的问题。在下面的代码中,在Test 中,对M 的最后一次调用无法解析(它无法编译)。错误是:调用在[M 的前两个重载]之间不明确

static void M(Func<int> f) { }
static void M(Func<string> f) { }
static void M(Func<dynamic> f) { }

static dynamic DynamicObject() {
    return new object();
}

static void Test() {
    M(() => 0);
    M(() => "");
    M(() => DynamicObject()); //doesn't compile
}
  1. 为什么,由于类型不是静态已知的,它不能解析为接受dynamic 的重载吗?
  2. 重载方法甚至可以使用dynamic吗?
  3. 解决此问题的最佳方法是什么?

【问题讨论】:

  • 在这里使用泛型不是更好吗?它仍然是模棱两可的(记住动态可以是A也可以是B,编译器怎么知道要调用哪个?)。但是,如果您愿意,我认为您可以将方法更改为static void M&lt;T&gt;(Func&lt;DataTime, T&gt; f) where T : Astatic void M&lt;T&gt;(Func&lt;DataTime, T&gt; f) where T : B,我认为这将允许重载? - 当然Test中的所有方法调用都应该没问题?
  • 这个例子是人为的,但准确反映我的困境的一个部分是将dynamic 传递给一个重载的方法。如何最好地解决?
  • 如上所述 - 不要。如何重载一个可以是任何东西的对象?
  • @Smudge:当然你可以接受object 的重载。请参阅 Tigra 的工作示例。
  • 不要那样做!改用泛型!

标签: c# dynamic overloading overload-resolution


【解决方案1】:

这里的问题是类型推断。编译器试图根据参数找出要使用的重载,但它也试图根据所选的重载找出参数的类型。对于M(() =&gt; DynamicObject()),流程如下:

  1. 该方法的参数是一个零参数的 lambda。这为我们提供了所有三种重载的可能性。
  2. lambda 的主体返回 dynamic。因为存在从 dynamic 到任何其他类型的隐式转换,所以我们现在知道所有三个重载都是好的。
  3. 尝试选择最佳过载。在大多数情况下,“最佳”是指派生最多的类型。因为intstring 都派生自object,所以intstring 的重载被认为是最好的。
  4. 我们现在有两个“最佳”重载,这意味着编译器实际上无法选择其中之一。编译失败。

现在,关于您的问题的可能解决方案:

  1. 使用强制类型转换或类型化局部变量明确 lambda 的类型:

    M((Func<dynamic>)(() => DynamicObject()));
    

    Func<dynamic> f = () => DynamicObject();
    M(f);
    
  2. 将动态重载重命名为 DynamicM。这样,您就不必处理重载决议。

  3. 我觉得这个有点不对:确保dynamic 重载是唯一适合的,通过转换为object

    M(() => (object)DynamicObject())
    

【讨论】:

  • 啊,我没想到Func 是逆变的。我认为dynamic/object 处于逆变位置是问题的根源。我仍然想知道为什么它没有在可能的匹配列表中包含 dynamic 重载。
  • @Daniel,这与逆变无关。如果Func 不是逆变的,也会发生同样的事情。并且编译器确实在第一遍中包含了dynamic 重载,但它没有将它包含在“最佳”匹配之一中。
  • 明白了。您选择最具体的重载是对的。我将第一个重载更改为接受Func&lt;A&gt; 和第二个Func&lt;B&gt;B 派生自A),它解析为第二个。奇怪,但真实。
【解决方案2】:

来自MSDN中的定义:

dynamic

在大多数情况下,动态类型的行为类似于类型对象。然而, 不解析包含动态类型表达式的操作 或类型由编译器检查。编译器打包在一起 有关操作的信息,该信息稍后用于 在运行时评估操作。作为过程的一部分,变量 动态类型的被编译成对象类型的变量。所以, 动态类型只存在于编译时,不存在于运行时

所以编译时动态不存在,因为它需要将其转换为destination *type*,这就是为什么无法解析它的原因。什么是目的地类型?

事实上,如果你这样做:

static void M(Func<int> f) { }
static void M(Func<string> f) { }
static void M(Func<object> f) { } // could be also declared like dynamic here, works by the way

static object DynamicObject()
{
    return new object();
}

static void Test()
{
    M(() => 0);
    M(() => "");
    M(() => DynamicObject());
}

它可以按照您的意愿完美运行,因为 object 在编译时就已经像类型一样存在,与必须转换dynamic 类型不同。

【讨论】:

  • 你的例子正好说明了为什么我认为它起作用,因为dynamic 只是object。有没有办法让dynamic 使用重载解析?
  • No:) dynamic 不是一个对象,它必须在编译时转换为某种类型,但在这种情况下,无法理解哪个类型必须是它的目标......
  • 好的,回到我原来的问题:有没有办法让重载接受dynamic,或者它永远不会解决?
  • 恕我直言,不可能,我也从未见过动态类型的重载。想看看其他帖子。
  • 你不是在描述泛型提供的确切功能吗?你似乎对dynamic这个词很感兴趣,但这不是你的追求吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多