【问题标题】:Access information in a List of a abstract class访问抽象类列表中的信息
【发布时间】:2020-11-24 01:19:03
【问题描述】:

我有下面显示的代码。我创建了一个动物列表(“List”),在其中添加了几个 Cat、Dog 和 Bird。是否可以直接访问每个类的不同字段,例如狗的年龄或猫的颜色列表?

谢谢!

public abstract class Animals
{
}


public class Cat : Animals
{
    public string Name;
    public string Color;
    public int Age;
    public string Breed  
}


public class Dog : Animals
{
    public string Name;
    public string Color;
    public int Age;
    public string Breed
}

public class Bird : Animals
{
    public string Name;
    public int Age;
    public string Wing_Color;
    public string Fly_Height;
}

【问题讨论】:

  • 你应该把通用属性放在 Animals 类中。并用编程语言标记问题
  • public abstract class Animals 不应有复数名称。应该是public abstract class Animal

标签: c# list inheritance abstract-class


【解决方案1】:

是否可以通过该列表直接访问每个类别的不同字段,例如狗的年龄或猫的颜色?

是的,但前提是您在编译时知道类型。

C# (尚)不支持正确的代数类型或可区分联合,因此要进行详尽检查,您需要使用is 运算符(最好使用a Code Analysis package like ExhaustiveMatching)或定义自己的Match 方法.

像这样:

方法一:使用is操作符:

is 运算符的这种用法有时被称为“模式匹配”——但我不同意这个术语,因为它实际上只是对运行时类型检查语法的人体工程学改进,而不是 真正的 em>(在 Haskell 意义上)数据的模式匹配。

List<Animal> animals = ...

foreach( Animal a in animals )
{
    if( a is Cat cat )
    {
        Console.WriteLine( "Cat breed: {0}.", cat.Breed );
    }
    else if( a is Dog dog )
    {
        Console.WriteLine( "Dog breed: {0}.", dog.Breed );
    }
    else if( a is Bird bird )
    {
        Console.WriteLine( "Bird name: {0}.", bird.Name );
    }
    else
    {
        throw new InvalidOperationException( "Unknown animal subclass." );
    }
}

ExhaustiveMatching 之类的代码分析包如果您定义了一个 closed 类型层次结构(如 Java 风格的枚举类)并且您正在切换(使用C# 7.x switch 语句与 case TypeName name:-syntax)但缺少子类案例。

方法2:使用自定义匹配/切换方法:

定义自定义 MatchSwitch 方法允许您要求使用调用站点是详尽无遗的,但这取决于您的 Match/Switch 方法是否详尽 - 但随着它转移负担 -对您负责 - 而不是对消费者负责 - 这种方法具有优势。

像这样:

abstract class Animal
{
    public TResult Match<TResult>(
        Func<Cat ,TResult> isCat,
        Func<Dog ,TResult> isDog,
        Func<Bird,TResult> isBird
    )
    {
        if     ( this is Cat  c ) return isCat( c );
        else if( this is Dog  d ) return isDog( d );
        else if( this is Bird b ) return isBird( b );
        else                      throw new InvalidOperationException( "Unknown animal subclass." );
    }
}

这样使用:

foreach( Animal a in animals )
{
    String summary = a.Match(
        isCat : c => "Cat breed: " + c.Breed,
        isDog : d => "Dog breed: " + d.Breed,
        isBird: b => "Bird name: " + b.Name,
    );

    Console.WriteLine( summary );
}

【讨论】:

    【解决方案2】:

    由于你所有的动物都有名字和年龄,我建议使用更好的设计并将这些字段移动到抽象父类并为它们定义抽象 getter:

    public abstract class Animal
    {
        public string Name;
        public int Age;
        abstract string getName();
        abstract int getAge();
    }
    
    
    public class Cat : Animal
    {
        public string Breed  
    }
    
    
    public class Dog : Animal
    {
        public string Color;
        public string Breed
    }
    
    public class Bird : Animal
    {
        public string Wing_Color;
        public string Fly_Height;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      • 2019-07-09
      • 2011-10-15
      • 1970-01-01
      • 1970-01-01
      • 2011-11-20
      • 2012-11-14
      相关资源
      最近更新 更多