gpt4 book ai didi

vb.net - 为什么不能将 IView(Of SpecificViewModel) 转换为 IView(Of ViewModelBase)?

转载 作者:行者123 更新时间:2023-12-03 10:20:56 26 4
gpt4 key购买 nike

这是 MVVM + WPF,但实际上与这些工具没有太大关系。问题比较笼统,属于OO设计。

昨天 MarcinJuraszek 帮助我提出了一个很好的解决方案来解决 original problem .该解决方案解决了手头的问题,但现在我陷入了下一个层次。事情是这样的:

查看模型

我的 ViewModel 类继承自一个通用的抽象父 ViewModel 类:

Public MustInherit Class ViewModelBase
Implements INotifyPropertyChanged, IDisposable

...

End Class

具体的 ViewModel 如下所示:
Class SalesOrderEntryViewModel
Inherits ViewModelBase
Implements IEditorViewModel, IChildViewModel

...

End Class
IEditorViewModelIChildViewModel是我的一些具体 ViewModel 实现的接口(interface)。

浏览量

我所有的 View 类都实现了以下接口(interface):
Interface IView(Of T As ViewModelBase)
WriteOnly Property MyVM As T
ReadOnly Property HeaderText As String
End Interface

基于 SalesOrderEntryViewModel 的具体 View 我上面描述的定义为:
Class SalesOrderEntryPage
Implements IView(Of SalesOrderEntryViewModel)

End Class

到现在为止还挺好。我现在面临的实际问题是我想在应用程序级别创建所有打开的 View 的强类型集合。这个集合的类型应该是什么?我尝试了类似以下的方法:
Dim Views As List(Of IView(Of ViewModelBase))

当我尝试添加 SalesOrderEntryPage 的对象时类到这个列表,它会抛出一个运行时异常,告诉我它不能从 SalesOrderEntryPage 转换。至 IView(Of ViewModelBase) ,尽管查看定义, SalesOrderEntryPage真的是 IView(Of ViewModelBase) .

目前,VB.NET 正在帮助我进行后期绑定(bind),但我想知道为什么会这样说,在这方面什么是优雅的解决方案?

最佳答案

您面临的问题与泛型的使用有关,并且与称为泛型类型参数变化的概念有关。泛型接口(interface)的类型参数可以是不变的、协变的或逆变的。

默认情况下,通用接口(interface)的类型 T 是不变的。这意味着,您可以将 T 用作方法参数的类型,也可以用作方法的返回类型。不利的一面是,这意味着以下任何一项都不可能:

Cast IView(Of ViewModelBase) to IView(Of SalesOrderEntryViewModel)

Cast IView(Of SalesOrderEntryViewModel) to IView(Of ViewModelBase)



这是有道理的,当您考虑:

  • 假设 IView(Of T)有一个需要 的方法 类型的参数T : 这意味着 IView(Of SalesOrderEntryViewModel)有一个方法,它需要一个类型为 SalesOrderEntryViewModel 的参数.但如果你能投IView(Of SalesOrderEntryViewModel)IView(Of ViewModelBase) , 你会期望它有一个参数类型为 ViewModelBase 的方法,但它没有,因为该方法是为 SalesOrderEntryViewModel 类型的参数设计的仅适用于其通用版本或其他源自 ViewModelBase 的 ViewModel .结果:您不能将 IView(Of SalesOrderEntryViewModel) 转换为 IView(Of ViewModelBase)。


  • 假设 IView(Of T)有一个方法 返回 T 类型的值 并假设类上的方法实现了IView(Of ViewModelBase)将返回 SalesOrderEntryViewModel ,这没关系,因为 SalesOrderEntryViewModelViewModelBase 的一个实例.到目前为止,一切都很好。但是,如果您现在尝试将此类转换为 IView(Of SomeOtherViewModel ,它不再起作用了,因为你的方法想要返回的类型 SalesOrderEntryViewModel不是 SomeOtherViewModel 的实例.结果:您不能将 IView(Of ViewModelBase) 转换为 IView(Of SalesOrderEntryViewModel)。


  • 但:

    有一种方法可以绕过这些限制,但您必须选择:

    您可以在 T 中使您的界面逆变。 : 这意味着你不能使用 T 作为你的方法的返回类型,但你可以强制转换 Interface(Of Base)Interface(Of Derived) .
    Interface IContravariant(Of In A)
    Sub SetSomething(ByVal sampleArg As A)
    Sub DoSomething(Of T As A)()
    ' The following statement generates a compiler error.
    ' Function GetSomething() As A
    End Interface

    或者你在 T 中使你的接口(interface)协变。 : 那么你不能有接受 T 类型参数的方法, 但你可以投 Interface(Of Derived)Interface(Of Base) .
    Interface ICovariant(Of Out R)
    ' The following statement generates a compiler error
    ' because you can use only contravariant or invariant types
    ' in generic contstraints.
    ' Sub DoSomething(Of T As R)()
    End Interface

    这就是理论。

    对于您的特殊情况:

    When I try to add an object of SalesOrderEntryPage class to this list, it throws a run-time exception telling me that it cannot convert from SalesOrderEntryPage to IView(Of ViewModelBase)



    所以,你想从接口(interface)(派生)转换为接口(interface)(基础)。这意味着,您需要使您的界面 IView ViewModelType 中的协变。因此,您失去了通过 IView 设置 ViewModel 的能力。界面。

    所以,它并没有真正解决问题,但我希望它能让你清楚,为什么它不起作用,你想要做什么。

    我建议为您的所有 View 定义一个逆变或非泛型基本接口(interface)。我做了后者,虽然它包含的内容不多(非泛型 IView(Model) 接口(interface)),但它让生活变得更轻松。然后派生一个允许设置 View 的 ViewModel 的接口(interface)。通过这种方式,您可以使用 readonly 填充您的收藏。您的 View 的版本。

    关于vb.net - 为什么不能将 IView(Of SpecificViewModel) 转换为 IView(Of ViewModelBase)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15424349/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com