簡體   English   中英

從實現的泛型轉換為接口類型的泛型

[英]Cast from something Generic of implementing to something Generic of interface type

也許很容易,但是請看一下以下類/接口:

public interface IChallenge
public interface IChallengeView<T> where T : IChallenge 
{
    T Challenge {get;set;}
}
public interface IChallengeHostView
{
    IChallengeView<IChallenge> ChallengeView { get; set; }
}

public class AdditionChallenge : IChallenge {}
public class AdditionChallengeView: IChallengeView<AdditionChallenge> {}

該方案是針對幼兒的教學應用程序。 我打算通過將主機(可以是任何圖形化的環境)與要解決的挑戰分開來保持應用程序的靈活性。 這樣,我可以在相同的環境中進行加法,乘法,除法...

現在,當我想充實自己的生活時,我遇到了轉換問題:

HostView hostView = new HostView();  // implements IChallengeHostView
AdditionChallengeView challengeView = new AdditionChallengeView();
hostView.ChallengeView = challengeView;

當然,這是行不通的。 我知道為什么不這樣做,但是我不知道如何解決這個問題。

有任何想法嗎?

更新 :我之前決定發布盡可能少的代碼,但是這使我陷入了向你們隱藏一個問題的麻煩:接口IChallengeView具有可設置的屬性(現在在上面的代碼中可見),這使得協方差變為不可能在此應用-通用類型參數只能在這種情況下是不變的。

rich.okelly給出的答案是正確的,但基於錯誤的假設(再次基於我在此處的描述所給出的較差的詳細程度)。

我決定使代碼的實現類型粘合劑少一些,如下所示:

public interface IChallenge
public interface IChallengeView
{
    IChallenge Challenge {get;set;}
}
public interface IChallengeHostView
{
    IChallengeView ChallengeView { get; set; }
}

public class AdditionChallenge : IChallenge {}
public class AdditionChallengeView: IChallengeView {}

這意味着我在AdditionChallengeView(以及所有其他實現類)中還有一些強制轉換代碼,但是在我看來,這是當時唯一可行的方法。

如果您使用的是c#4(或更高版本),則可以利用方差。 嘗試將您的IChallengeView<T>接口聲明為協變,如下所示:

public interface IChallengeView<out T> where T : IChallenge {}

分離出使用協變方式使用類型參數的接口部分和使用一個互變方式使用接口的部分通常很有用。 這通常需要使用“ SetProperty”方法而不是讀寫屬性(出於某種原因(如果接口繼承了一個接口,該接口包括一個只讀屬性Foo ,而另一個接口實現一個只寫屬性Foo ,則出於某種原因),編譯器會說,任何對屬性訪問的嘗試都是“模棱兩可的”,並且不允許foo被讀取或寫入,盡管事實是讀訪問只能引用只讀屬性,而寫訪問只能寫屬性。 ,將一個接口的協變和協變方面分開通常會允許人們在有幫助且有意義的情況下使用方差;此外,將接口中讀取對象的部分分開通常還是有幫助的。

一個小注意事項:我建議使用接口時,請使用以下術語來表示所表示的含義:

  • 一個“可讀”的foo接口應該提供一種讀取對象特征的方法,但是不能保證該對象是否可以使用其他某種方式來寫入。

  • “只讀” foo接口不僅應提供一種讀取對象特征的方法,而且還應保證可以公開對任何合法實現的引用而無需公開對對象的寫方法。 但是,不能保證沒有其他可以修改對象的方法。

  • “不可變的” foo接口應保證觀察到的具有給定值的任何屬性將始終具有該值。

如果代碼需要簡單地讀取對象中的內容,則可以要求輸入“ IReadableFoo”。 如果代碼使用對象引用作為短期封裝數據的對象,而該對象希望將其公開給其他代碼,但不允許將對象本身公開給任何可能對其進行修改的對象,則應將對象包裝在只讀包裝器中除非它可以安全地直接公開該對象(這由實現IReadOnlyFoo的對象指示。)如果代碼想要保留引用作為在其中持久保存數據快照的一種方式,則應在可能的情況下復制該對象它可能會更改,但如果對象將始終相同(由IImmutableFoo指示),則IImmutableFoo

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM