我在尝试访问实现类的接口属性时遇到了问题。问题是,我在运行时只有特定的(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>
的原因。并非我创造的所有孩子都会坐着宠物。这开始听起来令人毛骨悚然。
答案 0 :(得分:0)
IPetSitter<Animal>
,您无法将其投放到IPetSitter<Cat>
。
你可以反过来做,假设Cat:Animal。
此:
((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
{
...
}
这样,它是通用的,并将其限制为动物或源自Animal的东西,无论是直接还是间接。
但是,如果您将其初始化为new NeighborhoodKid<Animal>()
,则无法将其视为(也称为转换为)IPetSitter<Cat>
,因为它被初始化为IPetSitter<Animal>
(因为为NeighborhoodKid构造函数提供的泛型T参数是Animal,并传递给IPetSitter泛型参数。)
答案 1 :(得分:0)
问题在于你定义了
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; }
}
答案 2 :(得分:0)
为什么不只是Timmy.Pet = new Cat();
?
只需将其设为public
即可全部设置:
public class NeighborhoodKid : Kid, IPetSitter<Animal>
{
public Animal Pet { get; set; }
}
如果你创建一个不从IPetSitter
继承的NeighborhoodKid,那么setter就不可用了。
public class LazyNeighborhoodKid : Kid
{
// Nothing here, hes not a Pet Sitter, can access Pet
}
答案 3 :(得分:0)
除了他们在收藏中的实用性之外,我并不真正喜欢泛型,这就是原因。您强制每个NeighborhoodKid绑定到一个特定类型的Animal。如果蒂米可以看猫或狗怎么办?你打算为每个人创建不同的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;
}
}
}
如果您将执法留在实例级别,那么您不一定需要使用具体的强制转换来设置属性。