我有一个功能,列出动物,其中一些是狗,其中一些只是动物。该函数将该列表返回给想要仅提取狗的不同函数,这是可能的,因为Animal类有一个bool isDog。
我的问题是,是否可以从动物(父)类中提取特定于狗的(特定于孩子的)数据。一只动物还能成为引擎盖下的狗吗?
我尝试过的事情:
我有这两个接口
public interface IAnimal
{
string eyeColor;
int numLegs;
}
public interface IDog: IAnimal
{
double tailLength;
}
和这两个实现
public class Animal: IAnimal
{
public string eyeColor{get;set}
public int numLegs {get; set;}
public bool isDog;
public Animal(string eyes, int legs){
this.eyeColor = eyes;
this.numLegs = legs
this.isDog = false;
}
}
public class Dog: Animal, IDog
{
public double tailLength {get;set;}
public Dog(double tail, string eyes)
{
this.tailLength = tail;
this.eyeColor = eyes;
this.numLegs = 4;
this.isDog = true;
}
}
这是两个函数的当前状态
List<Animal> getAnimals()
{
List<Animal> animals;
Animal a1 = new Animal("Blue", 4);
animals.Add(a1);
Animal a2 = new Animal("Green", 2);
animals.Add(a2);
Dog d1 = new Dog(2.3, "Brown");
animals.Add(d1);
Dog d2 = new Dog(3.5, "Black");
animals.Add(d2);
return animals;
}
void foo(){
IEnumerable<IAnimal> sample = getAnimals();
var x = totalTailLength(sample.Where(d => d.isDog));
}
double totalTailLength(IEnumerable<IDog> dogs){
return dogs.Sum(d => d.tailLength);
}
由于
答案 0 :(得分:5)
不,当然,特定于子类的数据不会丢失。
但请:
如果您只需要提取狗类动物,您只需使用Linq:
IEnumerable<IDog> dogs = animals.OfType<IDog>();
答案 1 :(得分:5)
你不能这样做。这样:
sample.Where(d => d.isDog)
将返回IEnumerable<Animal>
,因为那是您的收藏中的类型。数据不会丢失,但您正在使用Animal
类型,但您不了解Dog
属性。
您希望实际从您的收藏中获取Dog
类型,例如:
sample.OfType<Dog>()
如果调试代码,可以在调试器中查看运行时的基础属性。尝试一下,您就可以看到集合中的真实类型。
答案 2 :(得分:5)
是的,你绝对可以这样做。如果您使用确切的代码并修复了一些错误,那么您可以看到它有效:
错过分号有两种语法错误。
字段不能是接口成员,因此您需要将它们设为属性。
Dog
需要调用父的构造函数,这也无需手动设置这些属性:
public Dog(double tail, string eyes) : base(eyes, 4)
{
this.tailLength = tail;
this.isDog = true;
}
在getAnimals
中,您需要初始化列表:
List<Animal> animals = new List<Animal>();
在foo
中,sample
的类型为IEnumerable<IAnimal>
,因此元素的类型为IAnimal
。但是,该类型没有isDog
属性(因为它在类上,但在接口上没有)。因此,要么将类型更改为IEnumerable<Animal>
,要么将成员移动到界面。
totalTailLength
预计会有IDog
个sample.Where()
,但IAnimal
会返回Animal
s(或var x = totalTailLength(sample.Where(d => d.isDog).Cast<IDog>());
s,如上所述)。由于您过滤了元素,因此应该强制使用可枚举:
Dog
然后一切都会编译 - 如果你真的打印出结果 - 你会得到正确的结果。
对象的类型不会附加到引用该对象的变量,而是附加到对象本身。因此,动物清单中的每个isDog
仍然知道它是一只狗。这实际上允许您摆脱IAnimal someAnimal = new Dog();
bool isADog = someAnimal is Dog; // true
成员,因为您可以使用is
operator检查对象是否属于特定类型:
Dog
您还可以使用LINQ来使用Enumerable.OfType<T>
过滤IAnimal
列表的var x = totalTailLength(sample.OfType<IDog>());
元素:
FOO
答案 3 :(得分:3)
没有数据丢失。这堂课不会成为狗。您所要做的就是将其强制转换为子类型,数据将在那里等着您。