使用LINQ时无法隐式地将类转换为基类IEnumerable.ToDictionary()

时间:2013-09-06 16:37:41

标签: c# linq abstract-class .net-4.5 implicit-conversion

我有以下情况令我感到困惑。

假设:

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");

3 个答案:

答案 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)

这与协方差有关。 ThermoRawFileMSDataFile,但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)
);