2010-12-05 3 views
2

Я пытаюсь перебрать список элементов. Элементы являются частью общего интерфейса. Они описаны в разделе this question. Я хочу использовать цикл foreach, чтобы пройти через них, но выполнять различные действия в зависимости от того, какой тип он есть.Итерирование списка различных типов данных?

Для простоты предположим, что действия, которые я хочу, чтобы выполнить следующие:

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

Как это может быть достигнуто итерация для учета различных типов данных?

ответ

2

Предполагая, что вы определили правильные перегрузки для ProcessLine(), вы просто проверяете типы этих объектов во время каждой итерации, а затем выполняете соответствующие действия и вызываете метод. Что-то вроде этого:

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

Чтобы улучшить дизайн программы, вы можете рассмотреть другие предложения здесь (добавить метод Process() к интерфейсу, и т.д.).

+0

вау! почти тот же код :) – Lorenzo 2010-12-05 23:01:50

+0

@Lorenzo: Я сначала написал `instanceof`, но на самом деле` is`. Мог бы исправить ваш код тоже :) – BoltClock 2010-12-05 23:02:24

+0

+1 ты абсолютно прав! ;) – Lorenzo 2010-12-05 23:04:57

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

Я бы серьезно рассмотреть, если это является наиболее подходящим дизайн в этом контексте. Вы уверены, что интерфейс 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
foreach (var m in list){ 
    if (m is MachineLine) ProcessLine((MachineLine) m); 
    else if (m is MachineCircle) ProcessLine((MachineCircle) m); 
} 
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) 
} 
2

лучший способ справиться с этим IMHO заключается в том, чтобы типы наследовались от общего базового класса/интерфейса, который имеет метод, который выполняет требуемое действие. Затем вызовите общий метод в цикле. В вашем случае я бы сделал его базовым классом, потому что это - отношения и добавьте метод 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(); 
} 

Пусть полиморфизм сделает для вас работу.

0

Решение Джеффа является первым выбором, альтернативно, если для вас сейчас слишком много изменений, вы также можете использовать функцию перегрузки.

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

вы можете использовать ключевое слово динамический, если вы работаете в .net 4.0

foreach (dynamic m in machineList) { 

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

} 
Смежные вопросы