为什么我不能在接口上调用ToString()方法?

9

我在创建一个样例控制台应用程序时遇到了不同的问题,因此我非常想知道发生了什么。

最初的问题是,在我的代码中,我有一个名为ICat的类,这个类是用C#编写的。

public interface ICat
{
  string ToString(CatColour colour);
}

在相同的程序集中,使用C#实现如下:
public class MagicCat : ICat
{
        public string ToString(CatColour colour)
        {
            return $"I am a {colour} cat";
        }
}

这段代码可以无误编译。

在另一个使用VB.NET编写的程序集中,我有以下代码:

Dim myCat As ICat = GetCat()
Dim result = myCat.ToString() ' Error on this line

这会导致编译器错误,提示“未为'Function ToString(format As AddressFormat) As String'的参数'colour'指定参数。”

我尝试在C#应用程序中重新创建此代码:

public class Cat : IAnimal
{
    public string ToString(CatColour colour)
    {
        return $"I am a {colour} cat.";
    }

    //public string ToString()
    //{
    //    return "I am a cat.";
    //}
}

public interface IAnimal
{
    string ToString(CatColour colour);
}

class Program
{
    static void Main(string[] args)
    {
        IAnimal cat = new Cat();

        Console.WriteLine(new Cat().ToString());
        Console.WriteLine(new Cat().ToString(CatColour.Red));

        Console.WriteLine(cat.ToString());
        Console.WriteLine(cat.ToString(CatColour.Blue));

        Console.ReadKey();
    }
}

public enum CatColour
{
    Red = 1,
    Blue = 2
}

它编译并运行,输出结果为:

ConsoleApplication1.Cat
我是一只红猫。
ConsoleApplication1.Cat
我是一只蓝猫。

(如果我取消注释另一个ToString()方法,则第一行将变为> 我是一只猫。)

这正是我所期望的。

我将应用程序转换为VB.NET,期望得到上述原始错误,但实际上我遇到了这个问题:

Public Class Cat
    Implements IAnimal
    Public Function ToString(colour As String) As String
        Return "I am a {colour} cat."
    End Function
End Class

Public Interface IAnimal
    Function ToString(colour As String) As String
End Interface

类 'Cat' 必须为接口 'IAnimal' 实现 'Function ToString(colour As String) As String'

这里发生了什么?为什么VB.NET在我的接口实现中给我一个错误,为什么我的原始场景抱怨没有不带参数的ToString()方法?


编辑:我已经更新了我的VB代码:

Public Interface IAnimal
    Function ToString(colour As String) As String
End Interface

Public Class Cat
    Implements IAnimal
    Public Function ToString(colour As String) As String Implements IAnimal.ToString
        Return "I am a {colour} cat."
    End Function
End Class

Sub Main()

    Dim cat As Cat = New Cat()
    Dim icat As IAnimal = New Cat()

    Call cat.ToString()
End Sub

我遇到了一个问题:Public Function ToString(colour As String) As String的参数'colour'未指定,这是原始问题,在C#代码中没有出现。有什么想法吗?Cat是一个对象,因此它上面有一个空的ToString()方法。


你需要明确地实现你的接口方法。为什么我不能在接口上调用ToString()方法?可能是因为接口不继承自Object类。 - Amit Kumar Ghosh
在你的C#版本中,你定义了两个'ToString'方法的版本,一个带参数,一个不带参数。但是在VB版本中,只有带参数的版本存在。我认为你需要重写那个方法。这意味着需要进行显式实现。 - Abhishek Anand
我想你可以这样说,为什么在VB.NET中调用ToString()方法时需要将其添加到接口中才能被调用,而C#却不需要,因为ToString()Object的一个方法,而Cat是一个对象? - NibblyPig
注意:我本以为你希望在返回的字符串前加上$,这样颜色才能真正替换字符串(很高兴看到有人知道如何正确拼写"colour") - Matt Wilko
我看到了你问题的解决方案。虽然这是个合法的问题,但我不会把接口成员命名为 ToString,即使有不同的签名,因为它可能会与所有对象都继承自 ObjectToString() 函数混淆。;-) - shadow
我认为这是C#允许隐式接口实现以及您使用的问题。如果您的C#类显式实现了IAnimalToString方法,例如string IAnimal.ToString(CatColour colour),那么您将在C#中看到与VB中相同的问题。 - TnTinMn
2个回答

7
你需要添加更多信息:

您需要添加更多的信息:

Public Class Cat
     Implements IAnimal
     Public OverLoads Function ToString(colour As String) As String Implements IAnimal.ToString
         Return $"I am a {colour} cat."
     End Function
End Class

Public Interface IAnimal
    Function ToString(colour As String) As String
End Interface

或者

Public Class Cat
     Implements IAnimal
     Public Function MyToString(colour As String) As String Implements IAnimal.ToString
         Return $"I am a {colour} cat."
     End Function
End Class

啊哈!这使得VB.NET部分的行为符合我的预期。然而,它不允许我调用没有参数的 ToString(),即使是 New Cat().ToString() 也不行。 - NibblyPig
1
正确地添加字符串重载可能已经避免了需要完全调用实现的必要性... - Trevor
添加“Overloads”似乎已经解决了问题。我很想知道为什么在VB.NET中需要这样做。在我的原始问题中,我无法将其添加到接口中,因为它是用C#编写的,而没有这样的关键字。 - NibblyPig
这是因为您重载了在基类(object)中定义的函数。 - tumasgiu
我猜这是VB.NET的一个怪癖,需要进行指定。有趣的是,如果在C#程序集中实现接口,则会出现破坏性问题。在我的情况下,我可以编辑引用的程序集以添加另一个ToString()实现并重新发布NuGet包,这仍然是hacky的,但如果它是第三方方法,我将无法在VB.NET中正确使用它。真是太奇妙了。 - NibblyPig
显示剩余2条评论

2

您可能需要为带参数的ToString()声明Overloads(因为您有另一个基于Object派生的基本ToString()),并且重写没有参数的从Object派生的ToString()

Public Class Cat
    Implements IAnimal
    Public Overloads Function ToString(colour As String) As String Implements IAnimal.ToString
        Return "I am a {colour} cat."
    End Function
    Public Overrides Function ToString()
        Return "I am a cat."
    End Function
End Class

Public Interface IAnimal
    Function ToString(colour As String) As String
End Interface

或者,您可以为IAnimal创建两个ToString(),并覆盖来自IAnimal而不是Object的无参数ToString()

Public Class Cat
    Implements IAnimal
    Public Overloads Function ToString(colour As String) As String Implements IAnimal.ToString
        Return "I am a {colour} cat."
    End Function
    Public Overrides Function ToString() As String Implements IAnimal.ToString
        Return "I am a cat."
    End Function
End Class

Public Interface IAnimal
    Function ToString(colour As String) As String
    Function ToString() As String
End Interface

我认为这是必须的。 - Abhishek Anand
无法覆盖它(即使编译器发出警告说需要覆盖),因为如果这样做,会出现错误,指出没有具有该签名的函数可供覆盖。 - NibblyPig
显然,“Overloads”关键字可以解决这个问题,但由于我的接口在C#程序集中,所以无法添加该关键字以便VB.NET能够正常工作。 - NibblyPig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接