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

时间:2010-12-05 22:56:43

标签: c# list foreach

我正在尝试迭代一个项目列表。这些项目都是通用界面的一部分。它们如this question中所述。我想使用foreach循环来完成它们,但根据它的类型执行不同的操作。

为简单起见,让我们说我想要执行的操作如下:

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

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

9 个答案:

答案 0 :(得分:5)

我会认真考虑这是否是此上下文中最合适的设计。您确定IMachine界面不应该有Process方法吗?每台机器都可以适当地实现它,然后循环变为:

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(...);
    }
}

正如你所看到的,这种模式很难看。为了获得更清晰的解决方案,如果有大量实施者,您可能还需要查看C# - Is there a better alternative than this to 'switch on type'

答案 1 :(得分:3)

处理此IMHO的最佳方法是让类型继承自公共基类/接口,该接口具有执行所需操作的方法。然后在循环中调用common方法。在你的情况下,我会把它变成一个基类,因为它们是一个关系,并将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();
}

让多态为你工作。

答案 2 :(得分:2)

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

foreach (IMachine m in machineList) {
    if (m is MachineLine) {
        ProcessLine((MachineLine) m);
    } else if (m is MachineCircle) {
        ProcessLine((MachineCircle) m);
    }
}

为了改进您的程序设计,您可以在此处考虑其他建议(在您的界面中添加Process()方法等)。

答案 3 :(得分:1)

List<IMachine> m = new List<IMachine>();
foreach ( IMachine machine in m) {
    if (m is MachineLine) {
        ProcessLine( m as MachineLine );
    }
    else if (m is MachineCircle) {
        ProcessLine( m as MachineCircle );
    }
}

答案 4 :(得分:1)

foreach (var m in list){
  if (m is MachineLine) ProcessLine((MachineLine) m);
  else if (m is MachineCircle) ProcessLine((MachineCircle) m);
}

答案 5 :(得分:0)

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

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)
}

答案 6 :(得分:0)

这听起来像是游客设计模式的一个很好的候选人......

http://en.wikipedia.org/wiki/Visitor_pattern

答案 7 :(得分:0)

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)
{
....
} 

答案 8 :(得分:0)

如果您使用的是.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
}

}