2

尝试访问实现类上的接口属性时遇到问题。问题是,我在运行时只有特定的 (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>. 并非我创造的所有孩子都会坐着宠物。这听起来令人毛骨悚然。

4

4 回答 4

0

Timmy 最终被初始化为 NeighborhoodKid。这意味着宠物,对他来说,就是动物。Timmy 是IPetSitter<Animal>,您不能将其转换为IPetSitter<Cat>

不过,你可以反过来做,假设 Cat : Animal。

这个:

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

实际上工作只是因为 Timmy 真的是IPetSitter<Animal>,因为 NeighborhoodKid : IPetSitter<Animal>,所以你并没有真正对那个演员做任何事情 - 只是访问宠物财产。

之后的问题是无法访问 Pet 或将 Cat 放入其中 - 将 Timmy 投射到IPetSitter<Cat>这就是问题所在。你正在将它贬低为它不是的东西。

您始终可以向上转换,但只能向下转换为初始化对象的内容。

如果您希望 NeighborhoodKid 成为任何类型动物(包括动物本身)的 IPetSitter,您应该这样做:

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

这样,它是通用的,并且将其限制为是动物或从动物派生的东西,无论是直接还是间接。

不过,如果您将其初始化为new NeighborhoodKid<Animal>(),您将无法将其视为 (aka cast it to) IPetSitter<Cat>,因为它被初始化为IPetSitter<Animal>( 因为给 NeighborhoodKid 构造函数的通用 T 参数是 Animal ,并且被传递给IPeSitter 通用参数)。

于 2012-05-08T17:05:56.180 回答
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; }
}
于 2012-05-08T17:08:39.180 回答
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;
        }
    }
}

如果您将强制执行留在实例级别,那么您不一定需要使用具体铸造来设置属性。

于 2012-05-08T21:29:31.143 回答
0

为什么不只是Timmy.Pet = new Cat();?只要做到这一点public,你就会万事俱备:

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

如果您创建一个不继承自的 NeighborhoodKid IPetSitter,则 setter 将不可用。

public class LazyNeighborhoodKid : Kid
{
   // Nothing here, hes not a Pet Sitter, can access Pet
}
于 2012-05-08T17:25:47.907 回答