【问题标题】:CS0121 Ambiguous overloaded function call with char, int, double parameters implicitly converted to user-defined types in C#CS0121 含 char、int、double 参数的模糊重载函数调用在 C# 中隐式转换为用户定义类型
【发布时间】:2021-10-20 11:15:51
【问题描述】:

我有一些 C# 类,MyChar、Myint、MyDouble,它们包装了 char、int 和 double。每个都有一个从包装类型到用户定义类型的隐式转换运算符。我还有一组重载函数,ToString(MyChar)、ToString(MyInt)、ToString(MyDouble)。

我想通过传入一个文字 char 值来调用 ToString(MyChar),例如'一种'。但编译失败并出现 CS0121,“以下方法或属性之间的调用不明确:'ToString(MyChar)' 和 'ToString(MyInt)'”。如果我传入一个 int 值,我会遇到类似的问题。

    public class MyChar
    {
        private MyChar(char val) => Value = val;
        public static implicit operator MyChar(char val) => new MyChar(val);
        public char Value { get; }
    }
    public class MyInt
    {
        private MyInt(int val) => Value = val;
        public static implicit operator MyInt(int val) => new MyInt(val);
        public int Value { get; }
    }
    public class MyDouble
    {
        private MyDouble(double val) => Value = val;
        public static implicit operator MyDouble(double val) => new MyDouble(val);
        public double Value { get; }
    }

    public class ConversionTests
    {
        public void DoIt()
        {
            Console.WriteLine(ToString('A')); // CS0121
            Console.WriteLine(ToString(1)); // CS0121
        }

        private static string ToString(MyChar c) => $"{c.Value}";
        private static string ToString(MyInt i) => $"{i.Value}";
        private static string ToString(MyDouble d) => $"{d.Value}";
    }

我发现我可以通过添加从 MyInt 到 MyDouble 的隐式转换使编译器正确接受 int 值

    public class MyDouble
    {
        private MyDouble(double val) => Value = val;
        public static implicit operator MyDouble(double val) => new MyDouble(val);
        public static implicit operator MyDouble(MyInt val) => new MyDouble(val.Value);
        public double Value { get; }
    }
...
        public void DoIt()
        {
            Console.WriteLine(ToString('A')); // CS0121
            Console.WriteLine(ToString(1)); // now compiles :-)
        }

我想这是可行的,因为解析机制现在认为到 MyDouble 的转换现在是通过路线 1 -> MyInt -> MyDouble 进行的,这不能隐式发生,因为它需要两个用户定义的转换。同样,我可以通过添加另外两个隐式转换来正确解析ToString('A'):MyChar 到 MyDouble,以及 MyChar 到 MyInt。

这很好,因为它反映了 char、int 和 double 之间发生的隐式转换。但是谁能向我解释为什么上面发布的原始代码在没有额外转换的情况下无法编译,就像我这样一个简单的大脑可能理解的方式?

【问题讨论】:

  • A Char 可以隐式转换为 Intint 可以隐式转换为 double。鉴于My 类型的隐式转换,这意味着ToString('A') 可以由both ToString 方法处理。您可以删除除 ToString(MyInt) 之外的所有 ToString() 方法,并且代码仍然可以工作
  • 你想做什么?您是在尝试,还是这是实际问题的简化案例?
  • @PanagiotisKanavos 这是我在代码中发现的问题的最简单简化。我想提供一个完整的 API,所以我没有删除方法的奢侈。我想使用一个重载的名称,因为在用户的心目中,操作是一样的,不管它操作的类型是什么。我不明白的是,为什么没有选择转换 char -> MyChar 作为明确的转换,因为它比 char -> int -> MyInt 更接近。
  • 在问题本身中描述实际问题。 没有一个转换比另一个更接近。所有都需要隐式转换,因此没有一个比另一个更接近。对于这些示例,可以在隐式转换后调用多种方法。
  • as in the user's mind the operation is the same thing, irrespective of the type its operating on. 那为什么不使用泛型方法呢?提供一个实际问题的例子。您可以为所有类型使用通用接口,使用泛型方法或使用其他技巧

标签: c# implicit-conversion ambiguous-call


【解决方案1】:

char 可以隐式转换为 intint 可以隐式转换为 double。鉴于My 类型的隐式转换,这意味着ToString('A') 可以由两种 ToString 方法处理。

您可以删除除ToString(MyInt) 之外的所有ToString() 方法,代码仍然可以工作:

    public class ConversionTests
    {
        public void DoIt()
        {
            Console.WriteLine(ToString('A')); 
            Console.WriteLine(ToString(1));
        }

        private static string ToString(MyInt i) => $"{i.Value}";
    }

这将打印:

65
1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 2019-08-18
    • 2020-05-03
    相关资源
    最近更新 更多