在内部可重用库的通用C#类中,我想传递一个引用“映射到其他东西列表的东西”。那里传递的内容的数据类型不应该被库知道。此外,它们的存储方式也不应该是已知的,即今天的内存中保存的列表,以后可能是从按需读取的数据库表。
所以我以为我会写这个库类:
class GenericClass<T, U>
{
public void Foo(IDictionary<T, IEnumerable<U>> bar)
{
// do something
}
}
这是编译,但尝试传递具体实现不会:
class UsingClass
{
public static void Main(string[] args)
{
var c = new GenericClass<string, string>();
c.Foo(new Dictionary<string, List<string>>());
}
}
我遇到以下两个语法错误:
Filename.cs(46,13): error CS1502: The best overloaded method match for 'GenericClass<string,string>.Foo(System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>)' has some invalid arguments
Filename.cs(46,19): error CS1503: Argument 1: cannot convert from 'System.Collections.Generic.Dictionary<string,System.Collections.Generic.List<string>>' to 'System.Collections.Generic.IDictionary<string,System.Collections.Generic.IEnumerable<string>>'
使用IEnumerable
替换Foo()
声明中的List
修复了它,但这当然不是我想要的。
这真的不受C#(4.0)的支持,还是我只是遗漏了一些明显的东西?你会建议什么解决方法? (我确信这之前已经讨论了很多,所以链接到很好的描述也很好。)
是的,我应该可以为此编写自己的帮助程序类,但为什么必须这样做?
答案 0 :(得分:8)
是的,这确实不受支持。想象一下你的Foo方法看起来像这样:
public void Foo(IDictionary<T, IEnumerable<U>> bar)
{
T key = GetKeyFromSomewhere();
bar[key] = new U[10]; // Create an array
}
看起来没问题,不是吗?我们可以从U[]
转换为IEnumerable<U>
。
从调用者的角度来看,它并不是那么好 - 突然我们在字典中有一个string[]
引用值,当所有值都是List<string>
引用时! Bang擅长安全。
您可以将方法重写为:
public void Foo<TValue>(IDictionary<T, TValue> bar)
where TValue : IEnumerable<U>
这将让你获得字典的值 out 并隐式地将它们转换为IEnumerable<U>
...但是你只能输入正确的值类型进入字典,你不能只从U
值构建它。
从版本4开始,C#在受限制的情况下支持泛型差异。例如,这适用于C#4(当针对.NET 4时),但以前不会:
List<string> strings = new List<string>();
IEnumerable<object> objects = strings;
对于关于通用差异的批次更多信息,请参阅有关该主题的Eric Lippert's blog series。为你的大脑定期爆炸做好准备。