键入从基类集合中检查派生类

时间:2016-06-23 21:18:03

标签: c# inheritance collections derived-class base-class

我有几个派生类都来自同一个基类。

class Base {}
class ClassOne : Base {}
class ClassTwo : Base {}
class ClassThree : Base {}

假设我有这些类对象的数组,我需要遍历此数组并根据派生类类型执行特定操作。

Base[] objects;

foreach(Base entry in objects){
    //Check for class type to perform operations
}

我已经看了几种方法来解决这个问题。起初我尝试了catch块然后尝试施放捕获无效强制转换的对象然后尝试另一个强制转换。这看起来很乱,所以我试着做一次检查。

if(entry.GetType() == ClassOne){}
else if(entry.GetType() == ClassTwo){}

但这不起作用,因为它们都被认为是代码中该实例的Base类型。

我现在要解决的问题是添加一个包含所有派生类类型的枚举,并在创建对象时将其设置在构造函数中。

public enum DerivedClassType{
    Base,
    One,
    Two,
    Three
}

现在我的foreach有一个开关,可以在尝试施放之前检查该类型。

Base[] objects;

foreach(Base entry in objects){
    switch(entry.derivedClassType){
        case DerivedClassType.One:
            ((One)entry).DoOneStuff();
            break;
        case DerivedClassType.Two:
            break;
        case DerivedClassType.Three:
            break;
    }
}

在完成所有这些步骤之后,我想知道处理这类问题的正确方法是什么,因为这一切似乎都比它应该更复杂。

由于

3 个答案:

答案 0 :(得分:3)

根据类类型执行不同操作的正确方法是使用抽象方法。

abstract class Base
{
    public abstract void DoSomethingWithArg(string arg);
}

class ClassOne : Base
{
    public override void DoSomethingWithArg(string arg)
    {
        Console.WriteLine($"Class One says {arg}");
    }
}
class ClassTwo : Base
{
    public override void DoSomethingWithArg(string arg)
    {
        Console.WriteLine($"Class Two says {arg}");
    }
}

然后像这样使用它

Base[] objects;

foreach (Base entry in objects)
{
    entry.DoSomethingWithArg("Hello");
}

如果你真的想继续沿着潜在的不可维护代码的路径前进,你可以像这样实现它(需要C#6);

foreach (Base entry in objects)
{
    switch (entry.GetType().Name)
    {
        case (nameof(ClassOne)):
            // Do something
            break;
        case (nameof(ClassTwo)):
            // Do something else
            break;
    }
}

答案 1 :(得分:0)

这应该有效:

my_file = open('configs.txt', 'r')
license = []

for line in my_file:
    if line.startswith ("show license verbose"):
        license.append(line)
        for (i, line) in zip( range(1, 6), my_file ):
            license.append( line )

print( license )

答案 2 :(得分:0)

@Massimiliano Girardi指出了你的准时问题。只需使用原始循环中的var替换Base,就可以提取所需的类型信息。你可以避免走下enum的兔子洞。

你指出带有重写方法的类型层次结构不是每个问题的答案。

你可能会考虑一种更具功能性的方法,它比可以在switch语句或ifs系列中调用函数方法更具可读性,可测试性,并且我认为是可维护的。我给你留下了这个解决方案(你可以在这里玩它:https://repl.it/C59q/3):

using System;
using System.Collections.Generic;

class Base {}
class ClassOne : Base {
    public void doOne(){
       Console.WriteLine("doing one") ;
    }
}

class ClassTwo : Base {
    public void doTwo(){
        Console.WriteLine("doing two");
    }

}
class ClassThree : Base {
    public void doThree(){
            Console.WriteLine("doing three");
        }
}


class MainClass {

  static Base[] objects = {
    new ClassOne(),
    new ClassTwo(),
    new ClassThree()

  };    

  public static void Main (string[] args) {

    Action<ClassOne> ClassOneFunc = delegate(ClassOne o)
         {o.doOne();}; 
    Action<ClassTwo> ClassTwoFunc = delegate(ClassTwo o)
         { o.doTwo();}; 
    Action<ClassThree> ClassThreeFunc = delegate(ClassThree o)
         { o.doThree();};   

    var contents = new Dictionary<System.Type, Action<dynamic>>
        {
            {typeof(ClassOne), ClassOneFunc}, 
            {typeof(ClassTwo), ClassTwoFunc},
            {typeof(ClassThree), ClassThreeFunc},

        };

    Action<dynamic> worker = o => contents[o.GetType()](o); 





  foreach(var each in objects){
    worker(each);

  }
}}