C#转换继承的泛型接口



我很难想出一个接口。这是针对C#Windows窗体的MVP设计。我有一个IView类,它是我在表单类上实现的。还有一个IPresenter,我将其衍生为各种特定的演示者。每个Presenter将根据角色的不同对IView进行不同的管理,例如,使用AddPresenter打开对话框以输入一组新数据,而不是使用EditPresenter编辑现有数据,EditPresenter会将数据预加载到表单上。这些都继承自IPresenter。我想这样使用代码:

AddPresenter<ConcreteView> pres = new AddPresenter<ConcreteView>();

我基本上已经完成了这项工作,但这些演示者和他们管理的视图被捆绑到插件中,这些插件在运行时后加载,这意味着我需要一个Manager类,它作为插件接口,采用"mode"参数。此模式参数用于创建Add或Edit Presenter的工厂方法,但由于稍后会调用显示对话框,因此我需要通过IPresenter接口进行调用,如下所示:

private IPresenter<IView> pres;
public ShowTheForm()
{
    pres.ShowDialog();
}

现在,当涉及到AddPresenter的具体实例化时,我遇到了问题,比如说,对"pres"成员。以下是我所拥有的简化版本:

interface IView
{
    void ViewBlah();
}
interface IPresenter<V> where V : IView
{
    void PresBlah();
}
class CView : IView
{
    public void ViewBlah()
    {        
    }
}
class CPresenter<T> : IPresenter<T> where T : IView
{
    public void PresBlah()
    {
    }
}
private void button3_Click(object sender, EventArgs e)
{
    CPresenter<CView> cpres = new CPresenter<CView>();
    IPresenter<IView> ipres = (IPresenter<IView>)cpres;
}

这就是错误:

Unable to cast object of type 'CPresenter`1[MvpApp1.MainForm+CView]' to type 'IPresenter`1[MvpApp1.MainForm+IView]'.

Presenter和Generic类型规范都来自我所能告诉的接口的ARE子类,所以我不明白为什么它不会强制转换。

有什么想法吗?

Steve

问题在于泛型类型参数。如果您使接口参数协变,那么强制转换将起作用。

这是通过添加out关键字来实现的,比如:

interface IPresenter<out V> where V : IView
{
    void PresBlah();
}

您可以通过以下MSDN文章了解更多关于这一点的信息:Generics中的协方差和方差。具有协变类型参数的通用接口部分专门适用于您的问题。

更新:确保你检查了@phoog和我之间的注释。如果你的实际代码接受V作为输入,你将无法使其协变。引用的文章和@phoog的回答更详细地解释了这个案例

CPresenter<CView>不是IPresenter<IView>,就像List<int[]>不是IList<IEnumerable>一样。

想想看,如果你能得到一个对List<int>IList<IEnumerable>引用,你就可以向它添加一个string[],这就必须抛出一个异常。静态类型检查的全部目的是防止编译此类代码。

如果接口允许,您可以将类型参数声明为协变(IPresenter<out V> where V : ...)。然后接口的行为将更像IEnumerable<out T>。只有当类型参数从未在输入位置使用时,这才有可能。

回到List<int[]>的例子,将其视为IEnumerable<IEnumerable>是安全的,因为不能向IEnumerable<T>引用添加任何内容;你只能从中读出东西,反过来,把int[]当作IEnumerable是安全的,所以一切都很好。

相关内容

  • 没有找到相关文章

最新更新