C#编译器的泛型,继承和失败的方法解析

Col*_*ett 6 c# generics compilation

我今天碰到了编辑问题,这让我感到困惑.考虑这两个容器类.

public class BaseContainer<T> : IEnumerable<T>
{
    public void DoStuff(T item) { throw new NotImplementedException(); }

    public IEnumerator<T> GetEnumerator() { }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { }
}
public class Container<T> : BaseContainer<T>
{
    public void DoStuff(IEnumerable<T> collection) { }

    public void DoStuff <Tother>(IEnumerable<Tother> collection)
        where Tother: T
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

前者定义DoStuff(T item),后者DoStuff <Tother>(IEnumerable<Tother>)专门用它来解决C#的协方差/逆变的缺失(直到4听到).

这段代码

Container<string> c = new Container<string>();
c.DoStuff("Hello World");
Run Code Online (Sandbox Code Playgroud)

遇到一个相当奇怪的编译错误.请注意<char>方法调用中没有.

类型'char'不能用作泛型类型或方法'Container.DoStuff(System.Collections.Generic.IEnumerable)'中的类型参数'Tother'.从'char'到'string'没有拳击转换.

从本质上讲,编译器试图我的电话果酱DoStuff(string)进入Container.DoStuff<char>(IEnumerable<char>),因为string工具IEnumerable<char>,而不是使用BaseContainer.DoStuff(string).

我发现进行此编译的唯一方法是添加DoStuff(T)到派生类

public class Container<T> : BaseContainer<T>
{
    public new void DoStuff(T item) { base.DoStuff(item); }

    public void DoStuff(IEnumerable<T> collection) { }

    public void DoStuff <Tother>(IEnumerable<Tother> collection)
        where Tother: T
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么编译器试图阻塞字符串,如IEnumerable<char>1)它知道它不能(假设存在编译错误)和2)它在基类中有一个编译好的方法? 我是否误解了C#中的泛型或虚拟方法的东西?难道还有其他的修复不是添加其他new DoStuff(T item)Container

Eoi*_*ell 3

编辑

好吧...我想我现在看到你的困惑了。您可能希望 DoStuff(string) 将参数保留为字符串,并首先遍历 BaseClass 方法列表寻找合适的签名,失败后回退到尝试将参数转换为其他类型。

但事情恰恰相反……相反,Container.DoStuff(string)嗯,“那里有一个符合要求的基类方法,但我要转换为 IEnumerable,并对当前类中可用的内容感到心脏病发作。 ..

嗯...我确信 Jon 或 Marc 此时能够用涵盖这个特定极端情况的特定 C# 规范段落来插话

原来的

两种方法都需要 IEnumerable 集合

您正在传递一个单独的字符串。

编译器正在获取该字符串,

好的,我有一个字符串,两种方法都需要一个IEnumerable<T>,所以我将这个字符串变成一个 IEnumerable<char>...完成

对,检查第一个方法... 嗯... 这个类是 a Container<string> 但我有一个 IEnumerable<char>所以这是不对的。

检查第二种方法,嗯......我有一个IEnumerable<char>但 char 没有实现字符串,所以这也不正确。

编译器错误

那么修复是什么,这完全取决于您想要实现的目标...以下两者都是有效的,本质上,您的类型使用在您的化身中是不正确的。

        Container<char> c1 = new Container<char>();
        c1.DoStuff("Hello World");

        Container<string> c2 = new Container<string>();
        c2.DoStuff(new List<string>() { "Hello", "World" });
Run Code Online (Sandbox Code Playgroud)