我正在尝试迭代一个项目列表。这些项目都是通用界面的一部分。它们如this question中所述。我想使用foreach
循环来完成它们,但根据它的类型执行不同的操作。
为简单起见,让我们说我想要执行的操作如下:
ProcessLine(MachineLine ML); //For MachineLines
ProcessLine(MachineCircle MC); //For MachineCircles
如何完成此迭代以考虑多种数据类型?
答案 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)
这听起来像是游客设计模式的一个很好的候选人......
答案 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
,则可以使用关键字dynamicforeach (dynamic m in machineList) {
if(m.GetType()==typeof(MachineLine))
{
// code goes here
}
else if(m.GetType()==typeof(MachineCircle))
{
// code goes here
}
}