使用动态参数的方法重载决策

发布于 2024-12-01 09:54:17 字数 618 浏览 1 评论 0原文

这可能之前已经回答过。我看到很多“动态方法重载解析”问题,但没有一个专门处理传递动态参数。在以下代码中,在 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. 既然类型不是静态已知的,为什么它不能解析为接受动态的重载?
  2. 重载方法是否有可能使用dynamic
  3. 解决这个问题的最佳方法是什么?

This may have been answered before. I see many "dynamic method overload resolution" questions, but none that deal specifically with passing a dynamic argument. In the following code, in Test, the last call to M cannot be resolved (it doesn't compile). The error is: the call is ambiguous between [the first two overloads of 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. Why, since the type isn't statically known, does it not resolve to the overload accepting dynamic?
  2. Is it even possible for an overloaded method to use dynamic?
  3. What is the best way to resolve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

李白 2024-12-08 09:54:17

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

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

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

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

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

    Func<动态> f = () =>动态对象();
    M(f);
    
  2. 将动态重载重命名为 DynamicM 之类的名称。这样,您就不必处理重载解析。

  3. 这对我来说有点不对劲:通过转换为对象,确保动态重载是唯一适合的重载:

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

The problem here is type inference. The compiler is trying to find out which overload to use based on the argument, but it's also trying to find out what the type of the argument is based on the chosen overload. In the case of M(() => DynamicObject()), the process goes something like this:

  1. The argument to the method is a lambda with zero parameters. This gives us all three overloads as possibilities.
  2. The body of the lambda returns dynamic. Because there is an implicit conversion from dynamic to any other type, we now know all three overloads are good.
  3. Try choosing the best overload. In most cases, “best” means the most derived type. Because both int and string derive from object, the overloads with int and string are considered best.
  4. We now have two “best” overloads, which means the compiler can't actually choose one of them. The compilation fails.

Now, regarding possible solutions to your problem:

  1. Make the type of the lambda explicit, either using cast or typed local variable:

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

    or

    Func<dynamic> f = () => DynamicObject();
    M(f);
    
  2. Rename the dynamic overload to something like DynamicM. This way, you don't have to deal with overload resolution.

  3. This one feels somewhat wrong to me: make sure the dynamic overload is the only one that fits, by casting to object:

    M(() => (object)DynamicObject())
    
筱武穆 2024-12-08 09:54:17

根据 MSDN 中的定义:

动态

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

因此编译时不存在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 类型不同,它必须被转变

From the definition in MSDN:

dynamic

Type dynamic behaves like type object in most circumstances. However,
operations that contain expressions of type dynamic are not resolved
or type checked by the compiler. The compiler packages together
information about the operation, and that information is later used to
evaluate the operation at run time. As part of the process, variables
of type dynamic are compiled into variables of type object. Therefore,
type dynamic exists only at compile time, not at run time

So dynamic doesn't exist when you compile, cause it needs to convert it into destination *type*, and that's why is not able to resolve it. What is destination type ?

In fact if you do something like this:

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());
}

It perfectly works as you want, as object is present like a type already at compile time, in difference of dynamic type which have to be converted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文