我正在跟踪一些代码,并向下面发送一个列表,以从列表中删除某些项目。
这是使用goto的正确方法吗?它甚至是必要的吗?你是不是只编辑了第二个if if else,并继续处理列表而不需要goto? (这是我第一次见到BASIC之外的goto。)
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
checkAB01:
for (int i = 0; i < src.Count; i++)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
)
{
src.Remove(info);
goto checkAB01;
}
if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.Remove(info);
goto checkAB01;
}
}
return src;
}
答案 0 :(得分:4)
LINQ怎么样?
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
return (from info in src.AsEnumerable<ClientEntity>()
where !(!String.IsNullOrWhiteSpace(info.ProductNumber) &&
info.CancelledByReliantSyncAB01 == (bool?)true)
where !(String.IsNullOrWhitespace(info.PartnerContract) &&
String.IsNullOrWhiteSpace(info.ProductNumber))
select info).ToList();
}
答案 1 :(得分:2)
不,这不是使用goto的正确方法,它只是一个不知道如何从列表中正确删除项目的人的替代品。 (向后迭代以防止跳过元素)
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count - 1; i >= 0; i--)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
)
{
src.RemoveAt(i);
}
if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.RemoveAt(i);
}
}
return src;
}
答案 2 :(得分:2)
我认为编写此代码的人不知道如何从迭代集合中删除项目。这些产品的原因是,一旦项目被删除,集合就会变小,这可能会导致迭代错误。
更好的一天是做一个反向循环。这样,您不必在删除后重复整个列表。下面的代码可以正常工作。
for (int i = src.Count - 1; i >= 0; i--) {
src.Remove(src[i]);
}
答案 3 :(得分:2)
正如其他人所说,这是goto
的使用率很低(应该很少,如果有的话),
总的来说,实施效率非常低。看起来它从0..N循环直到它移除了某些东西,然后从0..N(现在少了1)再次开始直到它移除了某些东西,依此类推。更糟糕的是,Remove
再次呼叫 从0..N开始寻找要删除的项目。
如果找不到任何要删除的内容,则返回。最好只做一个反向循环删除条目RemoveAt
然后返回。
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count - 1; i >= 0; i--)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true)
{
src.RemoveAt(i);
}
else if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.RemoveAt(i);
}
}
return src;
}
另外,我在那里添加了elseif
:执行另一个 if
检查似乎很危险,这可能是真的,并尝试重新删除相同的项目(特别是在改变指数)。
编辑:如果我们谈论可读的可用代码,我会将检查移到单独的方法中:
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count - 1; i >= 0; i--)
{
if (ShouldClientNotSendBack(src[i]))
src.RemoveAt(i);
}
return src;
}
private static bool ShouldClientNotSendBack(ClientEntity info)
{
if (!String.IsNullOrWhiteSpace(info.ProductNumber) && info.CancelledByReliantSyncAB01 == true)
{
return true;
}
if (!String.IsNullOrWhiteSpace(info.PartnerContract))
{
return true;
}
return false;
}
甚至可以考虑调整ShouldClientNotSendBack
方法和/或名称(甚至可能将两组if
检查移动到具有明确名称的单个方法),但我认为这是一个重大改进。
EDITx2:事实上,我会强烈考虑使用该方法。该方法在接收输入集合时显然返回IList<ClientEntity>
,这通常会向开发人员传达创建新列表,而实际上它实际上是变异现有列表并返回相同的列表实例。要么让它返回一个新列表(因此你应该更改循环代码以添加到新列表而不是从现有列表中删除)或删除返回类型,这样就更明显它正在改变传递的列表参数。
答案 4 :(得分:2)
正如我在评论中所述,在C#中使用goto
没有“正确”的方法。根据其定义,关键字是一个kludge;如果开发人员希望逐行翻译ASM或BASIC或其他语言的程序而没有定义的代码块,它隐藏了“跳跃”,那么它就是C / C ++的回归,其中包括它“以防万一”。过去常常进入他们之间。任何使用它的算法都可以重构而不必这样做,并且生成的算法将更具可读性。
在这种情况下:
public static IList<ClientEntity> FilterNoNeedSendBackToClients(IList<ClientEntity> src)
{
if (src == null)
return null;
for (int i = src.Count-1; i>=0; i--)
{
ClientEntity info = src[i];
if (info.ProductNumber != null && info.ProductNumber.ToLower().Trim().Length > 0
&&
info.CancelledByReliantSyncAB01 != null && info.CancelledByReliantSyncAB01.Value == true
)
{
src.Remove(info);
continue;
}
if ((info.PartnerContract == null || info.PartnerContract.Trim().Length == 0)
&&
(info.ProductNumber == null || info.ProductNumber.Trim().Length == 0))
{
src.Remove(info);
continue;
}
}
return src;
}
正如Chris Sinclair的回答所示,由于循环中条件的“或者/或”隐式结构,continue
语句不是必需的,但是我喜欢它们,因为它们显示编码器没有任何来自将指向循环结束的那一点,而不必阅读其余部分来确定。
如果您愿意,可以从前到后遍历列表,如果删除了某个项目,则在继续之前递减i
,以便循环将保持其在列表中的当前位置。有些人可能会说不这样做,因为对计数器的操作使得理解算法变得更加困难(并且因为在每次迭代时确定列表的计数稍微慢一些),但它在性能和可读性方面仍然要好得多。 goto
。