[英]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.