C# 从抽象类对象列表访问子类的属性

C# 从抽象类对象列表访问子类的属性,c#,oop,C#,Oop,我有一个抽象类Animal,它存储一些公共字段,例如name、health。我有很多动物类,例如Tiger,但我还有一个类Fish,它有一个其他动物类没有的额外字段,canSplash 然后我有一张动物物品的清单。我可以访问公共字段,但无法访问Fish的canSplash字段。我正在寻找从抽象类访问具体类特定字段的帮助 class Zoo { public List<Animal> animals = new List<Animal>(); public

我有一个抽象类Animal,它存储一些公共字段,例如name、health。我有很多动物类,例如Tiger,但我还有一个类Fish,它有一个其他动物类没有的额外字段,
canSplash

然后我有一张动物物品的清单。我可以访问公共字段,但无法访问Fish的
canSplash
字段。我正在寻找从抽象类访问具体类特定字段的帮助

class Zoo
{
    public List<Animal> animals = new List<Animal>();

    public Zoo()
    {
        animals.Add(new Monkey());
        animals.Add(new Tiger());
        animals.Add(new Fish());
    }

    public static void displayZooPopulation()
    {
        foreach (var a in animals)
        {
            if (a.species == "fish" && a.CanSplash)
            {
                Console.WriteLine("{0} can splash",a.Name);
            }
        }
    }
}

class Fish : Animal {
    private bool canSplash
    public bool CanSplash { get; set; }
}
class动物园
{
公共列表动物=新列表();
公共动物园()
{
添加(新猴子());
添加(新老虎());
添加(新鱼());
}
公共静态人口()
{
foreach(动物中的a型变种)
{
如果(a.species==“fish”&&a.CanSplash)
{
WriteLine(“{0}可以飞溅”,a.Name);
}
}
}
}
鱼类:动物{
私人厕所
公共bool CanSplash{get;set;}
}

简单的答案是,通过安全地强制转换到该类型来检查该类型,并检查它是否为
null

var fish = a as Fish;
if (fish != null && fish.CanSplash)
{
    Console.WriteLine("{0} can splash",a.Name);
}
如果您只有一个子类具有这种特定行为,那么这是完全可以的。 但是考虑到你还有其他动物类的动物也能飞溅,比如说大象,那么你也必须检查大象的类,如果你想找到你的动物园里所有可以扑扑的动物。 一个更好的方法是使用一个接口来处理诸如
ISplashable

public interface ISplashable
{
    bool CanSplash { get; }
}
现在,在您的所有子类中实现此接口,这些子类应该能够启动:

public class Fish : Animal, ISplashable
{
    // ...

    public bool CanSplash { get; set; }  // this also implements CanSplash { get; }

    // ...
}

public class Elephant : Animal, ISplashable
{
    // ...

    public bool CanSplash { get { return true; } }

    // ...
}
现在,您可以根据该接口而不是具体类进行检查:

var splasher = a as ISplashable;
if (splasher != null && splasher.CanSplash)
{
    Console.WriteLine("{0} can splash",a.Name);
}

//删除static关键字,因为您无法访问动物(或者动物应该是静态的)

检查a的类型,并采取行动

方法可以是:

 public   void displayZooPopulation() 
    {
        foreach (var a in animals)
        {
            if ( a is Fish)
            {
//here sure "a" is not null, no need to check against null
                var fish = a as Fish;
                //  if (a.species == "fish" && (Fish) a.CanSplash)
                if ( fish.CanSplash)
                {
                    Console.WriteLine("{0} can splash", a.Name);
                }
            }
        }
    }

顺便说一句,你说Animal是抽象类,Fish类中抽象方法的实现在哪里:)

为什么canSplash是bool而canSplash是float?为什么canSplash是私有的?canSplash是私有的,因为您使用get和set来访问它。抱歉,float是我键入此问题时犯的错误。请删除字段:private bool canSplash,您不需要它。如果您将canSplash设置为private,则需要一个额外属性的方法,以便其他类可以访问该属性。在这种情况下,您将执行两次类型检查,这是不必要的。您的方法是关于旧模式的
if(a是SomeClass){var c=(SomeClass)a;..
,这是低效的采取必要的措施。您使用接口进行的修改适用于大型复杂模型,而对于简单类模型则不需要。顺便说一句,在c#6中,为了检查空值,我们可以使用:if(splasher?.CanSplash):)您的“浓度”正是安全类型转换所做的。您的
if(a是鱼)
语句是不必要的,特别是如果您想使用新的C#6功能:
var fish=a as fish;if(fish?.CanSplash)…
。你说得对,简单的设计中不需要接口,但我在回答中指出了这一点……哇,谢谢你对接口的扩展回答,这不仅对本例非常有用,而且让我对接口的使用更加清楚。非常感谢!