C# 使用LINQ IEnumerable.ToDictionary()时未能将类隐式转换为基类

C# 使用LINQ IEnumerable.ToDictionary()时未能将类隐式转换为基类,c#,linq,abstract-class,.net-4.5,implicit-conversion,C#,Linq,Abstract Class,.net 4.5,Implicit Conversion,我有下面的情况,这让我很困惑 鉴于: public class ThermoRawFile : MsDataFile { } public abstract class MSDataFile { } 我无法运行此LINQ IEnumerable.ToDictionary()方法: 该错误并不是说它无法将CSMSL.IO.ThermoRawFile转换为CSMSL.IO.MSDataFile,只是它无法将基于CSMSL.IO.ThermoRawFile的通用字典类型转换为基于CSMSL.IO.

我有下面的情况,这让我很困惑

鉴于:

public class ThermoRawFile : MsDataFile { }

public abstract class MSDataFile { }
我无法运行此LINQ IEnumerable.ToDictionary()方法:


该错误并不是说它无法将
CSMSL.IO.ThermoRawFile
转换为
CSMSL.IO.MSDataFile
,只是它无法将基于
CSMSL.IO.ThermoRawFile
的通用字典类型转换为基于
CSMSL.IO.MSDataFile
的通用字典类型。这是意料之中的,因为这些类型不是协变的

您可以通过提供强制转换来解决此问题:

IEnumerable<string> rawFiles;
Dictionary<string, MSDataFile> dataFiles = rawFiles.ToDictionary(
    file => file,
    file => (MSDataFile)new ThermoRawFile(file)
);
IEnumerable原始文件;
字典数据文件=rawFiles.ToDictionary(
file=>file,
文件=>(MSDataFile)新的ThermoRawFile(文件)
);

问题在于类型推断已将您的
ToDictionary
调用推断为:

rawFiles.ToDictionary<string, string, ThermoRawFile>(...)
或者,您可以直接显式指定类型参数:

var dataFiles = rawFiles.ToDictionary<string, string, MSDataFile>(
    file => file,
    file => new ThermoRawFile());
var dataFiles=rawFiles.ToDictionary(
file=>file,
file=>new ThermoRawFile());

这仍然可以,因为编译器可以将lambda表达式
file=>new ThermoRawFile()
转换为
Func
这与协方差有关。
ThermoRawFile
是一个
MSDataFile
,但是
字典
不是
字典

如果是,那么你可以这样做:

public class FooFile : MsDataFile { }

dataFiles["blah"] = new FooFile();
这将是把一个
foo文件
放入
字典
,这将造成各种破坏

在这种情况下,您需要首先构造一个实际类型为
dictionary
的字典,即使您完全使用
ThermoRawFile
值填充它。您可以通过添加一个cast(如这里的一系列其他答案所示)来实现这一点:

IEnumerable原始文件;
字典数据文件=rawFiles.ToDictionary(
file=>file,
文件=>(MSDataFile)新的ThermoRawFile(文件)
);

为什么不使用实际的强制转换,而不是像那样使用
?通常,
as
的存在意味着转换可能会失败,并将通过空值检查进行处理。@JonSkeet你是对的,这有点误导。这个问题现在已经解决了。谢谢@穆普:如果你声明了错误信息,而不仅仅是“不起作用”,那就真的很有帮助了。我马上就看。@Moop:现在修好了。只是类型参数的数量不对。
rawFiles.ToDictionary<string, string, ThermoRawFile>(...)
var dataFiles = rawFiles.ToDictionary(
    file => file,
    file => (MSDataFile) new ThermoRawFile());
var dataFiles = rawFiles.ToDictionary<string, string, MSDataFile>(
    file => file,
    file => new ThermoRawFile());
public class FooFile : MsDataFile { }

dataFiles["blah"] = new FooFile();
IEnumerable<string> rawFiles;
Dictionary<string, MSDataFile> dataFiles = rawFiles.ToDictionary(
    file => file,
    file => (MSDataFile)new ThermoRawFile(file)
);