优化For循环结果
本文关键字:结果 循环 For 优化 | 更新日期: 2023-09-27 18:18:46
我目前使用这段代码来检查DataReader是否有列存在:
public static class DataRecordExtensions
{
public static bool HasColumn(this IDataRecord dr, string columnName)
{
for (int i=0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
}
我经常重用这段代码,因此它在For循环中连续运行。
我能优化这个吗?例如,如果一列不存在,那么这意味着所有结果都是相同的,我不必再次遍历所有内容。同样,如果它是存在的,我知道它是存在的,不需要再次进行循环。
谢谢!
该函数的代码很好。例如,你应该检查你的调用代码,不要在每次迭代你的DataReader或DataTable时都调用这个。
你应该调用这个方法一次之前迭代所有的记录。表或游标的每一行不具有相同列的可能性很小。
主要问题在于调用代码…但是你可以通过改变你的方法来创建并返回一个HashSet<string>
:
public static class DataRecordExtensions
{
public static ISet<string> GetFieldNames(this IDataRecord dr, StringComparer comparer)
{
var sequence = Enumerable.Range(0, dr.FieldCount)
.Select(i => dr.GetName(i));
return new HashSet<string>(sequence, comparer);
}
}
你可以用你的第一个记录调用这个方法,传递StringComparer.InvariantCultureIgnoreCase
作为比较器,你会得到一个ISet<string>
,你可以便宜地测试它是否包含一个特定的字段名。
尴尬的部分是可能只调用一次。您可能需要这样的内容:
ISet<string> fields = null;
while (reader.Read())
{
var record = ...;
if (fields == null)
{
fields = record.GetFieldNames(StringComparer.InvariantCultureIgnoreCase);
}
// Use fields and record here
}
您可能还想考虑返回Dictionary<string, int>
而不是ISet<string>
,如果您还需要字段数字。
一种选择是将列名存储在字典中,然后可以使用它非常快速地查找列名。
如果您正在使用扩展方法,则需要使用ConditionalWeakTable来存储和检索给定数据阅读器的字典。首先检查它是否存在,如果不存在,使用此方法缓存并存储它。
请记住,第一次调用这个方法时,它可能会比现在慢,因为你不能短路这个方法(因为你需要缓存所有的列名)。如果这是一个问题,你可以使用混合方法缓存到你找到你之后的列,然后退出,下次如果你没有在你的缓存中找到列,继续搜索和添加到缓存中的任何新列,再次退出一旦你找到你之后的列(或者你得到列的末尾)。
我应该说,这三种方法中哪一种是最好的(你目前的方法加上这两种)在很大程度上取决于:
- 为给定的数据读取器调用此方法的次数
- 数据阅读器中有多少列,和
- 按什么顺序搜索哪些列
例如,如果您的阅读器中有100列,并且搜索位置为97、98和99的列,那么我上面的第一种方法可能是最好的(第一次使用时缓存所有列)。但是,如果在位置1和100之间搜索列,那么混合方法可能更好。只要在任何地方搜索一次数据阅读器,您就可以更好地使用当前的方法!