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
?
编辑
好吧...我想我现在看到你的困惑了。您可能希望 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)