【问题标题】:Ambiguous constructor call error模棱两可的构造函数调用错误
【发布时间】:2014-10-21 02:10:07
【问题描述】:

我有一个名为Test 的类,它有一个constructor 接受Action<T>,另一个接受Func<T,T>。请看下面的sn-p。

public class Test<T>
{
    //constructors
    public Test() { }
    public Test(Action<T> action) { }
    public Test(Func<T, T> action) { }

    //methods with same signature of constructor
    public void MyMethod1(Action<T> action) { }
    public void MyMethod2(Func<T, T> action) { }
}


public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Test<string> t1 = new Test<string>(this.MyMethod1);
        Test<string> t2 = new Test<string>(this.MyMethod2);

        Test<string> t = new Test<string>();
        t.MyMethod1(MyMethod1);
        t.MyMethod2(MyMethod2);
    }

    public void MyMethod1(string value) { }
    public string MyMethod2(string value) { return string.Empty; }

}

但下面的行会引发一个模棱两可的调用错误

Test<string> t1 = new Test<string>(this.MyMethod1);
Test<string> t2 = new Test<string>(this.MyMethod2);

有趣的是,我有两个方法与我的 Testconstructor 的签名相同,它们不会引发任何模棱两可的错误

Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);

谁能帮我确定并解决问题。

【问题讨论】:

  • 请澄清:问题是“为什么分配不编译”还是“为什么分配不编译时方法调用编译”?
  • 请有金徽章的人将此作为this 的副本关闭。我重新打开以更改建议的重复项,但我不允许这样做:(

标签: c# oop constructor


【解决方案1】:

方法的返回值不是其签名的一部分。只考虑参数。因此,编译器无法区分Action&lt;T&gt;Func&lt;T,T&gt;。详细的解释和解决方法可以找到in this StackOverflow question

【讨论】:

  • @VimalCK 您有不同名称的方法。重命名方法以使用相同的名称并尝试。它不会编译。
  • 问题是您可以分配方法,但它们不会被调用,为了使您的应用程序正常工作,重命名构造函数的参数,如提到的 ngergo,但它们不会被调用,并实现此目的,在构造函数中添加调用,以便让方法得到执行。
【解决方案2】:

您可以尝试重命名每个构造函数的参数,如下所示:

public class Test<T>
{
    public Test() { }
    public Test(Action<T> action) { }
    public Test(Func<T,T> function) { }
}

所以当你实例化你的类时,你可以像这样指定参数的名称:

var objectWithAction = new Test<string>(action: Method1);
var objectWithFunction = new Test<string>(function: Method2);

【讨论】:

    【解决方案3】:

    事实

    方法/构造函数重载可以通过参数类型识别正确的方法但不包括返回类型。

    原因

    并且由于在问题中提到的两个构造函数调用中,参数都是 MethodGroup 类型,因此编译器无法确定正确的重载。其次,对方法的调用是成功的,因为在不重载的情况下。

    分辨率

    这里是解决问题的可能选项

    将方法调用封装成匿名方法调用,让隐式转换来区分自己。

        Test<string> t1 = new Test<string>(s => this.MyMethod1(s));
        Test<string> t2 = new Test<string>(s => { return this.MyMethod2(s); });
    

    结果


    替代方法

    其他选项是显式转换方法组

        Test<string> t1 = new Test<string>((Action<string>)this.MyMethod1);
        Test<string> t2 = new Test<string>((Func<string, string>)this.MyMethod2);
    

    如果参数较少,这比第一种方法要长一些

    【讨论】:

    • 这没有回答问题,你有什么解释为什么这解决了问题但方法组转换不起作用?
    • 我不想将它作为匿名传递...因为方法或函数将超过 10 行
    • @Selman22 我看不出修复有什么问题,因为它能够指向适当的构造函数。请参考截图。
    • @Selman22 此修复程序可能有效。但是考虑一下我要使用的方法有超过 15 行的情况。我想指向方法而不是匿名代码
    • @Selman22 看看第二种方法是否有益,除此之外,我没有看到任何其他替代方法来解决歧义。
    【解决方案4】:

    这里是一个工作控制台应用程序示例

    class Program
        {
            static void Main(string[] args)
            {
                Test<string> t1 = new Test<string>(action: MyMethod1);
                Test<string> t2 = new Test<string>(function: MyMethod2);
    
    
                Test<string> t = new Test<string>();
                t.MyMethod1(MyMethod1);
                t.MyMethod2(MyMethod2);
            }
            public static void MyMethod1(string value)
            {
                Console.WriteLine("my method1 {0}", value);
            }
            public static string MyMethod2(string value)
            {
                Console.WriteLine("my method2 {0}", value);
                return string.Empty;
            }
        }
        public class Test<T>
        {
            //constructors
            public Test() { }
            public Test(Action<T> action)
            {
    
                object args = "action";
                action.Invoke((T)args); // here you should invoke the method in order to execute it
            }
            public Test(Func<T, T> function)
            {
                object args = "function";
                function.Invoke((T)args);
            }
    
            //methods with same signature of constructor
            public void MyMethod1(Action<T> action)
            {
                object args = "Method 3";
                action.Invoke((T)args);
            }
            public void MyMethod2(Func<T, T> action)
            {
                object args = "Method 4";
                action.Invoke((T)args);
            }
        }
    

    希望对你有帮助

    问候

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-04
      • 2015-05-10
      相关资源
      最近更新 更多