2

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

鉴于:

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

为什么它不能隐式转换ThermoRawFileMSDataFile简单继承?

这工作得很好:

 MSDataFile dataFile = new ThermoRawFile("someFile.raw");
4

3 回答 3

3

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

您可以通过提供演员表来解决此问题:

IEnumerable<string> rawFiles;
Dictionary<string, MSDataFile> dataFiles = rawFiles.ToDictionary(
    file => file,
    file => (MSDataFile)new ThermoRawFile(file)
);
于 2013-09-06T16:41:49.450 回答
3

问题是类型推断推断您的ToDictionary调用是:

rawFiles.ToDictionary<string, string, ThermoRawFile>(...)

这意味着返回的值将是 type Dictionary<string, ThermoRawFile>,并且没有从 to 的转换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>.

于 2013-09-06T16:46:51.267 回答
0

这与协方差有关。AThermoRawFile是 a MSDataFile,但 aDictionary<string, ThermoRawFile>不是 a Dictionary<string, MSDataFile>

如果是,那么您可以执行以下操作:

public class FooFile : MsDataFile { }

dataFiles["blah"] = new FooFile();

这会将 aFooFile放入 aDictionary<string, ThermoRawFile>中,这会造成各种破坏。

在这种情况下,您需要构造一个实际上是类型的字典Dictionary<string, MSDataFile>,即使您使用完全ThermoRawFile值填充它。您可以通过添加演员来做到这一点(如这里的一堆其他答案所示):

IEnumerable<string> rawFiles;
Dictionary<string, MSDataFile> dataFiles = rawFiles.ToDictionary(
    file => file,
    file => (MSDataFile)new ThermoRawFile(file)
);
于 2013-09-06T16:47:53.713 回答