我有以下情况令我感到困惑。
假设:
public class ThermoRawFile : MsDataFile { }
public abstract class MSDataFile { }
我无法运行此LINQ IEnumerable.ToDictionary()方法:
IEnumerable<string> rawFiles;
Dictionary<string, MSDataFile> dataFiles = rawFiles.ToDictionary(
file => file,
file => new ThermoRawFile(file)
);
因为编译器出现以下错误:
"Cannot implicitly convert type System.Collections.Generic.Dictionary<string,CSMSL.IO.Thermo.ThermoRawFile> to System.Collections.Generic.Dictionary<string,CSMSL.IO.MSDataFile>"
为什么当它是一个简单的继承时,它不能将ThermoRawFile
隐式转换为MSDataFile
?
这很好用:
MSDataFile dataFile = new ThermoRawFile("someFile.raw");
答案 0 :(得分:3)
错误并未表示它无法将CSMSL.IO.Thermo.ThermoRawFile
转换为CSMSL.IO.MSDataFile
,只是因为它无法将基于CSMSL.IO.Thermo.ThermoRawFile
的通用字典类型转换为基于{{1}的通用字典类型}}。这是预期的,因为这些类型不是协变的。
您可以通过提供演员来解决此问题:
CSMSL.IO.MSDataFile
答案 1 :(得分:3)
问题是类型推断已将您的ToDictionary
调用推断为:
rawFiles.ToDictionary<string, string, ThermoRawFile>(...)
这意味着返回的值将是Dictionary<string, ThermoRawFile>
类型,并且没有从Dictionary<string, MSDataFile>
转换(部分原因是字典通常是不变的,部分原因是所有类都是不变的)。
现在你可以转换值选择部分以进行类型推断工作:
var dataFiles = rawFiles.ToDictionary(
file => file,
file => (MSDataFile) new ThermoRawFile());
或者您可以只显式指定类型参数:
var dataFiles = rawFiles.ToDictionary<string, string, MSDataFile>(
file => file,
file => new ThermoRawFile());
这仍然没问题,因为编译器可以将lambda表达式file => new ThermoRawFile()
转换为Func<string, MSDataFile>
。
答案 2 :(得分:0)
这与协方差有关。 ThermoRawFile
是MSDataFile
,但Dictionary<string, ThermoRawFile>
不是Dictionary<string, MSDataFile>
。
如果是,那么你可以这样做:
public class FooFile : MsDataFile { }
dataFiles["blah"] = new FooFile();
这会将FooFile
放入Dictionary<string, ThermoRawFile>
,这会造成各种各样的破坏。
在这种情况下,您需要构建一个实际上类型为Dictionary<string, MSDataFile>
的字典,即使您使用完全ThermoRawFile
值填充它也是如此。你可以通过添加一个演员表来实现这一点(如这里的一堆其他答案所示):
IEnumerable<string> rawFiles;
Dictionary<string, MSDataFile> dataFiles = rawFiles.ToDictionary(
file => file,
file => (MSDataFile)new ThermoRawFile(file)
);