C# 迭代不同数据类型的列表?

C# 迭代不同数据类型的列表?,c#,list,foreach,C#,List,Foreach,我正在尝试迭代一个项目列表。这些项都是公共接口的一部分。它们如中所述。我想使用一个foreach循环来遍历它们,但根据它的类型执行不同的操作 为了简单起见,假设我要执行的操作如下: ProcessLine(MachineLine ML); //For MachineLines ProcessLine(MachineCircle MC); //For MachineCircles 如何完成此迭代以考虑多个数据类型?假设已为ProcessLine()定义了适当的重载,只需在每次迭代期间测试这些对象

我正在尝试迭代一个项目列表。这些项都是公共接口的一部分。它们如中所述。我想使用一个
foreach
循环来遍历它们,但根据它的类型执行不同的操作

为了简单起见,假设我要执行的操作如下:

ProcessLine(MachineLine ML); //For MachineLines
ProcessLine(MachineCircle MC); //For MachineCircles

如何完成此迭代以考虑多个数据类型?

假设已为
ProcessLine()
定义了适当的重载,只需在每次迭代期间测试这些对象的类型,然后进行相应的强制转换并调用该方法。大概是这样的:

foreach (IMachine m in machineList) {
    if (m is MachineLine) {
        ProcessLine((MachineLine) m);
    } else if (m is MachineCircle) {
        ProcessLine((MachineCircle) m);
    }
}
<> P>为了改进程序设计,您可能希望在这里考虑其他建议(添加<代码>进程()/代码>方法到您的接口等).< /p> <代码>列表m=新建列表(); foreach(i机器,单位:m){ if(m为机械线){ 加工线(m为机械线); } else if(m为机械圆){ 工艺线(m为机械圆); } } 在这方面,我会认真考虑这是否是最合适的设计。您确定
IMachine
界面不应该有
过程
方法吗?每台机器都可以适当地实现这一点,然后循环就变成:

foreach (IMachine machine in machines)
{
    machine.Process();
}
无论如何,要回答这个问题,这里有一个方法。我们的想法是继续尝试对目标类型进行“投机性强制转换”,直到成功或我们别无选择。这通常是通过
as
操作符完成的,然后是
null
-测试

IList<IMachine> machines = ...

foreach (IMachine machine in machines)
{
    MachineLine machineLine = machine as MachineLine;

    if (machineLine != null)
        ProcessLine(machineLine);

    else
    {
        MachineCircle machineCircle = machine as MachineCircle;

        if (machineCircle != null)
            ProcessCircle(machineCircle);

        else throw new UnknownMachineException(...);
    }
}
IList机器=。。。
foreach(机器中的i机器)
{
机器线=机器作为机器线;
if(machineLine!=null)
加工线(机械线);
其他的
{
MachineCille MachineCille=机器为MachineCille;
if(machineCircle!=null)
过程循环(机械循环);
否则抛出新的未知机器异常(…);
}
}

如你所见,这种图案很难看。对于更干净的解决方案,您可能还想看看是否有大量的实现者

您应该将ProcessLine方法改为接受IMachine,并使其根据类型调用不同的方法。这将使代码更清晰,您以后可能会在其他地方重用该逻辑。像这样:

foreach (var m in list){
  if (m is MachineLine) ProcessLine((MachineLine) m);
  else if (m is MachineCircle) ProcessLine((MachineCircle) m);
}
foreach (IMachine m in machineList)
        ProcessLine(m);
ProcessLine中的代码如下所示:

void ProcessLine(IMachine machine)
{
   if (machine is MachineLine)
        ProcessMachineLine(MachineLine)
   else if (machine is MachineCircle)
        ProcessMachineCircle(MachineCircle)
}

这听起来也是访问者设计模式的一个很好的候选者


处理此IMHO的最佳方法是让类型从公共基类/接口继承,该基类/接口具有执行所需操作的方法。然后在循环中调用公共方法。在您的情况下,我会将其改为基类,因为它们是is-a关系,并将
ProcessLine()
方法添加到基类中

public abstract class MachineShape
{
    public abstract void ProcessLine();
}

public class MachineLine : MachineShape
{
    public override void ProcessLine()
    {
        // implement for MachineLine
    }

    public double X1;
    public double Y1;
    public double X2;
    public double Y2;
    public double Thickness;
}

public class MachineCircle : MachineShape
{
    public override void ProcessLine()
    {
        // implement for MachineCircle
    }

    public double CenterX;
    public double CenterY;
    public double Radius;
}

MachineShape[] shapes = ...;
foreach (var shape in shapes)
{
    shape.ProcessLine();
}

让多态性为您完成这项工作。

Jeff的解决方案是第一选择,或者,如果现在更改太多,您也可以使用函数重载

foreach (IMachine m in machineList){
        //sorry I can't test it since I don't have visual studio installed.
        //but you get the idea
        ProcessLine((m.getType())m);  
}

function ProcessLine(MachineLine m)
{
...
}

function ProcessLine(MachineCircle m)
{
....
} 

如果您在.net 4.0中工作,则可以使用关键字dynamic

foreach (dynamic m in machineList) {

 if(m.GetType()==typeof(MachineLine))
{
    // code goes here
}
else if(m.GetType()==typeof(MachineCircle))
{
    // code goes here
}

}

@洛伦佐:一开始我也写了
instanceof
,但实际上它是
的。可能也想修改你的代码:)当我输入我的代码时,似乎有大约3个都带有
instanceof
;我曾考虑过发表评论,但我想我会再补充一个答案。。。彼得:是的,
instanceof
/
总是让我着迷。我不得不提醒自己,
最近回到了c语言,并且今天正在用java编写
instanceof
,所以这在我的脑海中很新鲜。虽然简洁,使用这种技术,每种候选类型都有两个有效的强制转换操作。我会将强制转换从“m as MachineLine”更改为“(MachineLine)m”。您已经检查了对象的类型,使用“as”只是重复该检查。IMO还有两个使用
(MachineLine)m
的强制转换操作,一个强制转换操作既有is也有as。为了只执行1次强制转换,您必须使用as,但将结果保留在变量中,而不是使用is,将变量与null进行比较。+1用于在第一段中建议
IMachine.Process()
方法。
foreach (dynamic m in machineList) {

 if(m.GetType()==typeof(MachineLine))
{
    // code goes here
}
else if(m.GetType()==typeof(MachineCircle))
{
    // code goes here
}

}