繁体   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