使用类型泛型时如何正确地将类转换为抽象类? [英] How to correctly cast a class to an abstract class when using type generics?

查看:17
本文介绍了使用类型泛型时如何正确地将类转换为抽象类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下课程

public abstract class BaseViewPresenter { }
public abstract class BaseView<T> : UserControl
    where T : BaseViewPresenter { }

public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> {  }

我有一个看起来像这样的方法(简化)

I have a method that looks like this (simplified)

public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)
{
    var type = model.GetType();
    var viewType = _dataTemplates[type];

    // Correctly creates BaseView object
    var control = Activator.CreateInstance(viewType);

    // Fails to cast as BaseView<BaseViewPresenter> so returns null
    return control as BaseView<BaseViewPresenter>;
}

当我使用 LoginPresenter 的实例调用它时

When I call this using an instances of LoginPresenter

var login = new LoginPresenter();
var ctl = Resolve(login);

Activator.CreateInstance(viewType) 正确解析为我的 LoginView 的新实例,但是 control as BaseView 可以未正确执行转换,因此返回 null.

The line Activator.CreateInstance(viewType) correctly resolves into a new instances of my LoginView, however control as BaseView<BaseViewPresenter> can't do the cast correctly so returns null.

有没有一种方法可以在不使用特定类型泛型的情况下将 control 正确转换为 BaseView?

Is there a way to correctly cast the control into BaseView<BaseViewPresenter> without using specific type generics?

由于 LoginView 继承自 BaseView,并且 LoginPresenter 继承自 BaseViewPresenter,所以我假设有一种将 LoginView 转换为 BaseView 的方法.

Since LoginView inherits from BaseView<LoginPresenter>, and LoginPresenter inherits from BaseViewPresenter, I would assume there's a way to convert LoginView to BaseView<BaseViewPresenter>.

我坚持使用 .Net 3.5

I am stuck with using .Net 3.5

推荐答案

这是一个非常常见的问题.让我们重命名您的类型:

This is a very frequently asked question. Let's rename your types:

abstract class Fruit { }                    // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { }                     // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> {  }  // was LoginView

您现在的问题是:

我有一个 BowlOfApples,它继承自 FruitBowl.为什么我不能将它用作 FruitBowl?一个苹果就是一个水果,所以一碗苹果就是一碗水果.

I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.

不,它不是.你可以在一碗水果里放一根香蕉,但你不能在一碗苹果里放一根香蕉,因此一碗苹果不是一碗水果.(根据类似的论点,一碗水果也不是一碗苹果.)由于您可以对这两种类型合法执行的操作不同,因此它们不能兼容.

No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.

这是 StackOverflow 传奇人物 Jon Skeet 的照片,证明了这一事实:

Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:

你想要的特性叫做generic contravariance,只有在接口委托类型上被编译器证明方差是安全的,并且当变化类型是引用类型时.例如,您可以在需要 IEnumerable 的上下文中使用 IEnumerable,因为编译器可以验证您无法将Banana 变成水果的序列.

The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.

在此站点或网络上搜索C# 协变和逆变",您将找到有关此功能如何工作的更多详细信息.特别是,我关于我们如何在 C# 4 中设计和实现此功能的系列文章从这里开始:http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx

Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx

这篇关于使用类型泛型时如何正确地将类转换为抽象类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆