当前位置:  开发笔记 > 编程语言 > 正文

不明确的扩展方法调用

如何解决《不明确的扩展方法调用》经验,为你挑选了1个好方法。

此代码将无法编译:

using System;
using System.Runtime.CompilerServices;

static class Extensions {
    public static void Foo(this A a, Exception e = null, string memberName = "") {
    }

    public static void Foo(this A a, T t, Exception e = null, string memberName = "")
        where T : class, IB {
    }
}

interface IB { }

class A { }

class Program {
    public static void Main() {
        var a = new A();
        var e = new Exception();

        a.Foo(e); //<- Compile error "ambiguous call"
    }
}

但如果我删除最后一个string参数一切都很好:

    public static void Foo(this A a, Exception e = null) {
    }

    public static void Foo(this A a, T t, Exception e = null)
        where T : class, IB {
    }

问题是 - 为什么这些可选string参数会破坏编译器对方法调用的选择?

补充: 明确的问题:我不明白为什么编译器不能在第一种情况下选择正确的重载但是可以在第二种情况下进行?

编辑: [CallerMemberName]属性不是问题的原因所以我已经从问题中删除它.



1> 小智..:

@PetSerAl已经在评论中指出了规范,但是让我把它翻译成简单的英语:

C#语言有一条规则,即在没有省略默认参数的情况下,重载优先于带有省略的默认参数的重载.这个规则Foo(this A a, Exception e = null)比一个更好的匹配Foo(this A a, T t, Exception e = null).

C#语言没有规则说,带有一个省略的默认参数的重载优先于具有两个省略的默认参数的重载.因为它没有这样的规则,Foo(this A a, Exception e = null, string s = "")所以不是优先考虑的Foo(this A a, T t, Exception e = null, string s = "").

避免此问题的最简单方法通常是提供额外的重载,而不是使用默认参数值.您需要默认参数值CallerMemberName才能工作,但是您可以提供额外的重载来省略Exception,并通过传递null来转发到实际实现.

注意:确保Foo(this A a, T t, string s = "")Foo(this A a, Exception e, string s = "")可用时不会被挑选将是一个棘手的问题,无论如何.如果你的变量是静态类型的Exception,那么非泛型方法将是首选,但如果它是静态类型的,例如ArgumentException,那么T=ArgumentException是一个比基类更好的匹配Exception,并且T=ArgumentException将检测到错误太晚,无法选择方法你想打电话.放置T 之后 可能是最安全的Exception,并且总是需要在(可能null)传递异常时使用泛型方法.


@Szer是的,[泛型约束不是方法签名的一部分.](@ Szer是,泛型[约束不是方法签名的一部分.](https://blogs.msdn.microsoft.com/ericlippert/2009/一十分之一十二/约束-是 - 不部的最签名/)
推荐阅读
农大军乐团_697
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有