为什么编译器无法推断此选择调用的类型
本文关键字:选择 调用 类型 编译器 为什么 | 更新日期: 2023-09-27 18:33:08
>我正在尝试通过调用DTO列表中的选择来创建DTO的ViewModels列表。但是,编译器给了我一个错误,说:
方法的类型参数无法从用法中推断 尝试指定类型参数
我的问题是,为什么不能?TextSectionDTO
和ImageSectionDTO
都派生自SectionDTO
。我正在尝试创建一个Sections
List
,TextSection
和ImageSection
都派生自Section
。
我知道这个问题与这里发布的其他一些问题很接近,但我无法在那里找到答案。
这是我的代码:
private List<Section> BuildSectionViewModel(IEnumerable<SectionDTO> ss )
{
var viewModels = ss.Select((SectionDTO s) =>
{
switch (s.SectionType)
{
case Enums.SectionTypes.OnlyText:
return new TextSection((TextSectionDTO) s);
case Enums.SectionTypes.OnlyImage:
return new ImageSection((ImageSectionDTO) s);
default:
throw new Exception("This section does not exist - FIXME");
}
}).ToList();
return viewModels;
}
当我更改类型以便我只接受超类 SectionDTO 并只返回 Section 时(在这种情况下,我使它们都是普通类(,选择的工作方式就像您期望的那样。然后,当我将类型更改为仅文本部分DTO和文本部分(将摘要更改回来(时,选择不再起作用。
我想要一个解决方案,以便我可以让它与我现在拥有的结构一起工作,尽管我更感兴趣的是为什么它不能按原样工作。即使我能让它工作,我以后也可能会重构它。
注意:
- 我的目标是 MVC 4.5(所以编译器不是无法推断的旧版本,这是这里一些类似问题的解决方案(。
- switch 子句有一个默认情况,即错误不应该是由路径不返回值引起的。
case Enums.SectionTypes.OnlyText:
return new TextSection((TextSectionDTO) s);
case Enums.SectionTypes.OnlyImage:
return new ImageSection((ImageSectionDTO) s);
这两种情况返回不同的类型。编译器不够智能,无法检查这些类型是否派生自相同的基类型,因此您必须显式强制转换它们:
case Enums.SectionTypes.OnlyText:
return (SectionDTO) new TextSection((TextSectionDTO) s);
case Enums.SectionTypes.OnlyImage:
return (SectionDTO) new ImageSection((ImageSectionDTO) s);
为什么这不在编译器上实现?我认为这是因为编译器必须检查许多不同的类型。假设您的两种类型的Foo1
和Foo2
不是直接派生自Bar
而是从两个不同的类型(相应地Bar1
和Bar2
(派生,它们本身继承自Bar
。现在编译器应该检查Foo1
和Foo2
是否可以分配给它们不能分配给任何公共基类,并检查它们是否派生自具有公共基类(Bar
(的东西。最后,我们不得不检查整个继承链,直到object
,没有提到任何应该检查的接口。
class Foo1 : Bar1 {}
class Foo2 : Bar2 {}
class Bar1 : Bar {}
class Bar2 : Bar {}
Select
方法有两种类型-TSource
和TResult
。由于你在IEnumerable<SectionDTO>
上调用它,TSource
被推断为SectionDTO
,所以ss.Select((SectionDTO s) =>
是不需要的,可以只是ss.Select(s => ...
。
问题是在您的情况下无法推断出TResult
。为什么?您有两个回报 - TextSection
和 ImageSection
.它们不一样,它们都不是另一个的基础。你认为编译器应该推断什么?您认为答案应该是公共基类型Section
,但同样适用于公共基object
或两种类型的任何公共基类/接口。换句话说,结果是不明确的,因此编译器不会猜测您的意图,而是要求您显式指定。与三元运算符类似? :
仅在一个分支中指定公共基数就足够了,因此以下内容应该可以解决它
var viewModels = ss.Select(s =>
{
switch (s.SectionType)
{
case Enums.SectionTypes.OnlyText:
return (Section)new TextSection((TextSectionDTO) s);
case Enums.SectionTypes.OnlyImage:
return new ImageSection((ImageSectionDTO) s);
default:
throw new Exception("This section does not exist - FIXME");
}
}).ToList();