C# 从基类集合中检查派生类的类型

C# 从基类集合中检查派生类的类型,c#,inheritance,collections,derived-class,base-class,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

我有两个派生类,它们都来自同一个基类

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检查

if(entry.GetType() == ClassOne){}
else if(entry.GetType() == ClassTwo){}
但这不起作用,因为它们都被认为是代码中该实例的基类型

我现在所做的是添加一个包含所有派生类类型的枚举,并在创建对象时在构造函数中设置它

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;
    }
}
在经历了所有这些步骤之后,我想知道处理这类问题的正确方法是什么,因为这一切似乎比它可能应该的复杂得多


感谢

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

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)


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

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)

这应该起作用:

Base[] collection;

foreach(var item in collection){
    if((item as TypeYouWhant) == item){
        ...
    }
}
这应该起作用:

Base[] collection;

foreach(var item in collection){
    if((item as TypeYouWhant) == item){
        ...
    }
}

@马西米利亚诺·吉拉迪正确地指出了你的守时问题。只需在原始循环中用var替换Base,就可以提取所需的类型信息。你本可以避免进入枚举的兔子洞

您正确地指出,具有重写方法的类型层次结构并不是所有问题的答案

您可能会考虑一种更具可读性、可测试性的功能性方法,并且我认为它比在开关状态或IFS系列中调用函数方法更具可维护性。我留给你这个解决方案(你可以在这里玩:):

使用系统;
使用System.Collections.Generic;
类基{}
第一类:基本类{
公共空间{
Console.WriteLine(“做一件”);
}
}
第二类:基本类{
公开无效doTwo(){
Console.WriteLine(“做两件事”);
}
}
第三类:基础{
公共无效的doThree(){
控制台。写线(“做三个”);
}
}
类主类{
静态基[]对象={
新类一(),
新类二(),
新类别三()
};    
公共静态void Main(字符串[]args){
动作ClassOneFunc=委托(一级o)
{o.doOne();};
动作ClassTwoFunc=委托(Class2 o)
{o.doTwo();};
动作ClassThreeFunc=委托(ClassThree o)
{o.doThree();};
var contents=新字典
{
{typeof(ClassOne),ClassOneFunc},
{typeof(ClassTwo),ClassTwoFunc},
{typeof(ClassThree),ClassThreeFunc},
};
Action worker=o=>contents[o.GetType()](o);
foreach(对象中的每个变量){
工人(每人);
}
}}

@Massimiliano Girrdi正确地指出了你的守时问题。只需在原始循环中用var替换Base,就可以提取所需的类型信息。你本可以避免进入枚举的兔子洞

您正确地指出,具有重写方法的类型层次结构并不是所有问题的答案

您可能会考虑一种更具可读性、可测试性的功能性方法,并且我认为它比在开关状态或IFS系列中调用函数方法更具可维护性。我留给你这个解决方案(你可以在这里玩:):

使用系统;
使用System.Collections.Generic;
类基{}
第一类:基本类{
公共空间{
Console.WriteLine(“做一件”);
}
}
第二类:基本类{
公开无效doTwo(){
Console.WriteLine(“做两件事”);
}
}
第三类:基础{
公共无效的doThree(){
控制台。写线(“做三个”);
}
}
类主类{
静态基[]对象={
新类一(),
新类二(),
新类别三()
};    
公共静态void Main(字符串[]args){
动作ClassOneFunc=委托(一级o)
{o.doOne();};
动作ClassTwoFunc=委托(Class2 o)
{o.doTwo();};
动作ClassThreeFunc=委托(ClassThree o)
{o.doThree();};
var contents=新字典
{
{typeof(ClassOne),ClassOneFunc},
{typeof(ClassTwo),ClassTwoFunc},
{typeof(ClassThree),ClassThreeFunc},
};
Action worker=o=>contents[o.GetType()](o);
foreach(对象中的每个变量){
工人(每人);
}
}}

“根据派生类类型执行特定操作”-那么您使用的继承是错误的。请尝试非常明确地解释(不要使用名为base、one、two和three的人为示例,而是使用您的实际代码)为什么您认为需要这个。通常情况下,您根本不需要它,对它的需求也会消失。在每个类中添加一个overide方法,并使该方法执行不同的任务。那就是entry.method(),你有没有试过
if(entry.GetType()==typeof(ClassOne))
或者
if(entry是ClassOne)
?好吧,我试着让这个例子简单到只问我想要回答的问题。让我看看是否可以更明确一些。我有一个名为ObjectiveBase的基类,它具有我所有目标共享的功能。但我有不同类型的目标,比如ObjectiveZone、ObjectivePath、ObjectiveWatch。我的代码收集所有目标并存储