将Generic <Derived>转换为Generic <Base>

jue*_*n d 11 c# oop wpf casting covariance

我有一个基础WPF UserControl,它处理派生UserControls的一些常用功能.在任何派生的UserControl的代码隐藏中,我调用一个事件

private void SomeClick(object sender, RoutedEventArgs e) {
    HandleClick(sender);
    MyDataGrid.Items.Refresh();
}
Run Code Online (Sandbox Code Playgroud)

在我的基础UserControl我做

public class BaseUserControl : UserControl {
   protected void HandleClick(object sender) {
       var vm = (BaseViewModel<Part>)DataContext;
       ...
   }
}
Run Code Online (Sandbox Code Playgroud)

这会引发InvalidCastException,因为DataContext它是类型BaseViewModel但派生类型如BaseViewModel<Wire>BaseViewModel<Connector>.

我怎么能这样做?

nvo*_*igt 20

你不能投Generic<Derived>一个Generic<Base>.

想想你是否可以.你有一个List<Wolf>并把它投射到一个List<Animal>.现在,你可以.Add()一个SheepList<Animal>.但是等等......现在你的List<Wolf>包含了Sheep.真是一团糟.

只有在确保所投射的内容以所有可能的形式呈现为只读时,才能解决此问题.这是合作和逆转的全部.它只适用于接口.

  • 作为协方差可行的示例,请考虑接口`IReadOnlyList <out T>`.如果你有一个`IReadOnlyList <Wolf>`它会将_implicitly_转换为`IReadOnlyList <Animal>`.在这种情况下,"out"表示协方差(`in`将是逆变).正确的是,`class`类型不能像这样的共变和逆变(从当前版本开始).只有`interface`和`delegate`类型支持这种类型的共同和逆变. (5认同)
  • @Basic 从 `List&lt;Wolf&gt;` 到 `List&lt;Animal&gt;` 的转换不会创建新列表,也不会更改原始变量或实例的类型。这不是选角的作用。你仍然只有一个列表,最初声明为“List&lt;Wolf&gt;”,其中会有一只羊。 (4认同)
  • 抱歉,我不同意这种“混乱”的说法……你不会有一个包含羊的狼列表,你会有一个包含狼和羊的_动物_列表。这看起来完全合理。 (3认同)