亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用類型泛型時如何正確地將類轉換為抽象類?

使用類型泛型時如何正確地將類轉換為抽象類?

月關寶盒 2019-11-19 10:07:01
我有以下課程public abstract class BaseViewPresenter { }public abstract class BaseView<T> : UserControl    where T : BaseViewPresenter { }public class LoginPresenter : BaseViewPresenter { }public partial class LoginView : BaseView<LoginPresenter> {  }我有一個看起來像這樣的方法(簡化)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實例調用此函數時var login = new LoginPresenter();var ctl = Resolve(login);該行Activator.CreateInstance(viewType)正確解析為我的新實例LoginView,但是control as BaseView<BaseViewPresenter>無法正確進行強制轉換,因此返回null。有沒有一種方法可以正確地強制control轉換為BaseView<BaseViewPresenter>不使用特定類型的泛型?由于LoginView繼承自BaseView<LoginPresenter>和LoginPresenter繼承BaseViewPresenter,我假設有一種方法可以轉換LoginView為BaseView<BaseViewPresenter>。我堅持使用.Net 3.5
查看完整描述

3 回答

?
神不在的星期二

TA貢獻1963條經驗 獲得超6個贊

這是一個非常常見的問題。讓我們重命名您的類型:


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<Apple>。為什么不能將其用作FruitBowl<Fruit>?蘋果是一種水果,所以一碗蘋果是一碗水果。


不,不是。您可以將香蕉放在一碗水果中,但是不能將香蕉放在一碗蘋果中,因此,一碗蘋果不是一碗水果。(并且通過類似的論點,一碗水果也不是一碗蘋果。)由于您可以合法地對這兩種類型執行的操作是不同的,所以它們是不兼容的。


這是StackOverflow傳奇人物Jon Skeet的照片,展示了這個事實:


在此處輸入圖片說明


所需的功能稱為通用矛盾,當編譯器可以證明差異是安全的,并且變化類型是引用類型時,只有接口和委托類型才支持該功能。例如,您可以IEnumerable<Apple>在IEnumerable<Fruit>需要的上下文中使用an ,因為編譯器可以驗證沒有辦法將a Banana放入一系列水果中。


在此站點或網絡上搜索“ C#協方差和逆方差”,您將找到有關此功能如何工作的更多詳細信息。特別是,我有關如何在C#4中設計和實現此功能的系列文章從此處開始:http : //blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in -c-part-one.aspx


查看完整回答
反對 回復 2019-11-19
?
開心每一天1111

TA貢獻1836條經驗 獲得超13個贊

我接受了Eric的回答,因為它很好地解釋了為什么無法實現我想要的東西,但是我還認為我會分享我的解決方案,以防其他人遇到同樣的問題。


我從原始BaseView類中刪除了泛型類型參數,并創建了該類的第二個版本,BaseView其中包含了泛型類型參數及其詳細信息。


我的.Resolve()方法或其他不關心特定類型的代碼使用第一個版本,而任何不關心特定類型的代碼都使用第二個版本,例如BaseView


這是我的代碼最終看起來如何的示例


// base classes

public abstract class BaseViewPresenter { }

public abstract class BaseView : UserControl 

{

    public BaseViewPresenter Presenter { get; set; }

}


public abstract class BaseView<T> : BaseView

    where T : BaseViewPresenter

{

    public new T Presenter

    {

        get { return base.Presenter as T; }

        set { base.Presenter = value; }

    }

}


// specific classes

public class LoginPresenter : BaseViewPresenter { }

public partial class LoginView : BaseView<LoginPresenter> 

{

     // Can now call things like Presenter.LoginPresenterMethod()

}


// updated .Resolve method used for obtaining UI object

public BaseView Resolve(BaseViewPresenter presenter)

{

    var type = model.GetType();

    var viewType = _dataTemplates[type];


    BaseView view = Activator.CreateInstance(viewType) as BaseView;

    view.Presenter = presenter;


    return view;

}


查看完整回答
反對 回復 2019-11-19
  • 3 回答
  • 0 關注
  • 645 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號