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