簡體   English   中英

使用泛型進行轉換

[英]Casting with generics

嘗試訪問實現類上的接口屬性時遇到問題。 問題是,我在運行時僅具有特定的(Cat)類型,因此我的應用在嘗試投射時會中斷。

這是我所擁有的:

public class Animal {}
public class Cat : Animal {}

public interface IPetSitter {}
public interface IPetSitter<T> IPetSitter where T : Animal {
    T Pet { get; set; }
}

public class Kid { }

public class NeighborhoodKid : Kid, IPetSitter<Animal> {
    Animal Pet { get; set; }
}

// --- Implementation ---

// Kid Timmy is instantiated elsewhere
// Animal type "A" is passed in dynamically

if (Timmy is IPetSitter) {
    ((IPetSitter<A>)Timmy).Pet = new A();
}

如果類型不匹配,此轉換將出錯。 我想做這樣的事情:

public interface IPetSitter {
    object Pet { get; set; }
}

public interface IPetSitter<T> : IPetSitter where T : Animal {
    new T Pet { get; set; }
}

// --- Implementation ---

NeighborhoodKid Timmy = new NeighborhoodKid();
((IPetSitter)Timmy).Pet = new Cat();

但這迫使實現IPetSitter的任何東西都具有[object Pet]和[Cat Pet]屬性。

我將不勝感激。 謝謝。

更新:最初我應該使它更加清楚,但是有時我將創建一個Kid類,有時還會創建一個NeighborhoodKid類。 這就是為什么我需要轉換為IPetSitter<T> 並非我創造的所有孩子都是寵物。 這開始聽起來令人毛骨悚然。

最終,蒂米被初始化為NeighbourhoodKid。 對他來說,這意味着寵物就是動物。 Timmy是IPetSitter<Animal> ,您不能將其IPetSitter<Cat>IPetSitter<Cat>

不過,假設貓:動物,您可以反過來做。

這個:

((IPetSitter<Animal>)Timmy).Pet = new Cat();

實際上只起作用是因為Timmy實際上是IPetSitter<Animal> ,因為NeighborhoodKid: IPetSitter<Animal> ,所以您實際上並沒有對該演員做任何事情-只是訪問pet屬性。

之后的問題是,沒有訪問Pet,也沒有將Cat放入其中-這是將Timmy轉換為IPetSitter<Cat>的問題。 您正在將其貶低到並非如此。

您始終可以向上轉換,但是只能向下轉換到初始化對象所用的內容。

如果您希望NeighborhoodKid成為任何動物(包括動物本身)的IPetSitter,則應該執行以下操作:

public class NeighborhoodKid<T> : IPetSitter<T> where T : Animal
{
    ...
}

這樣,它是通用的,並將其限制為是動物或直接或間接源自動物的某種東西。

但是,如果將其初始化為new NeighborhoodKid<Animal>() ,則將其視為IPetSitter<Cat> (也稱為將其轉換為IPetSitter<Cat> ,因為它已被初始化為IPetSitter<Animal> (因為通用給NeighborhoodKid構造函數的T參數是Animal,並傳遞給IPetSitter通用參數)。

問題是您定義了

public class NeighborhoodKid : IPetSitter<Animal>
{
    Animal IPetSitter<Animal>.Pet { get; set; }
}

並不是

public class NeighborhoodKid : IPetSitter<Cat>
{
    Cat IPetSitter<Animal>.Pet { get; set; }
}

要么

public class NeighborhoodKid<T> : IPetSitter<T> where T : Animal
{
    Cat IPetSitter<T>.Pet { get; set; }
}

為什么不只是Timmy.Pet = new Cat(); 只需將其public ,一切就緒:

public class NeighborhoodKid : Kid, IPetSitter<Animal>
{
   public Animal Pet { get; set; }
}

如果您創建一個不繼承自IPetSitter ,則該設置程序將不可用。

public class LazyNeighborhoodKid : Kid
{
   // Nothing here, hes not a Pet Sitter, can access Pet
}

除了泛型在集合中的用途之外,我不是真正的泛型愛好者,這就是為什么。 您正在強迫將每個NeighborhoodKid綁定到一種特定的動物類型。 如果蒂米可以看貓或狗怎么辦? 您要為每個實例創建不同的Timmy實例嗎?

相反,我認為您是在實例級別強制使用動物類型。 例如(為簡潔起見,我將某些類型刪節了):

public interface IAnimal {...}

public class Cat : IAnimal {...}

public interface IPetSitter
{
    IAnimal Pet { get; set; }
}

public class Kid : IPetSitter
{
    public Kid (params Type[] allowedPets) {
        _allowedPets = allowedPets;
    }

    readonly IEnumerable<Type> _allowedPets;

    IAnimal _pet;
    public IAnimal Pet 
    {
        get {
            return _pet;
        }
        set {
            if (!_allowedPets.Contains(value.GetType()) {
                throw new InvalidArgumentException("This instance does not support " + value.GetType().Name + ".");
            }
            _pet = value;
        }
    }
}

如果您將執行保留在實例級別,則不必只使用混凝土澆鑄來設置屬性。

暫無
暫無

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

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