Answers:
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;
}
}
Exception
像在其他答案中一样,将s用于控制逻辑被认为是不好的做法,并且会降低性能。它还会将误报发送给抛出的#个异常的事件探查器,上帝可以帮助任何将调试器设置为打破抛出的异常的人。
GetSchemaTable()也是许多答案中的另一个建议。这不是检查字段是否存在的首选方法,因为不是所有版本都实现了它(它是抽象的,在dotnetcore的某些版本中会引发NotSupportedException)。GetSchemaTable也是性能过高的选择,因为如果您查看源代码,它是一个非常繁重的功能。
如果您经常使用这些字段,那么遍历这些字段可能会降低性能,并且可能需要考虑缓存结果。
最好使用以下布尔函数:
r.GetSchemaTable().Columns.Contains(field)
一个电话-没有例外。它可能会在内部引发异常,但我不这么认为。
注意:在下面的注释中,我们已经弄清楚了……正确的代码实际上是这样的:
public static bool HasColumn(DbDataReader Reader, string ColumnName) {
foreach (DataRow row in Reader.GetSchemaTable().Rows) {
if (row["ColumnName"].ToString() == ColumnName)
return true;
} //Still here? Column not found.
return false;
}
我认为最好的选择是在DataReader上调用GetOrdinal(“ columnName”),并在该列不存在的情况下捕获IndexOutOfRangeException。
实际上,让我们创建一个扩展方法:
public static bool HasColumn(this IDataRecord r, string columnName)
{
try
{
return r.GetOrdinal(columnName) >= 0;
}
catch (IndexOutOfRangeException)
{
return false;
}
}
编辑
好的,这篇文章最近开始获得一些反对意见,我不能删除它,因为它是公认的答案,所以我将对其进行更新,并(我希望)尝试证明使用异常处理作为控制流。
由Chad Grant发布的另一种实现方法是遍历DataReader中的每个字段,并对要查找的字段名称进行不区分大小写的比较。这将非常有效,并且实际上可能会比我上面的方法更好。当然,在涉及性能的循环中,我永远不会使用上面的方法。
我可以想到一种情况,在这种情况下,try / GetOrdinal / catch方法将在循环不起作用的地方工作。但是,现在这是一个完全假设的情况,因此这是一个非常脆弱的理由。无论如何,请忍受我,看看您的想法。
想象一下一个数据库,该数据库允许您“别名”表中的列。想象一下,我可以定义一个带有名为“ EmployeeName”的列的表,但也为其赋予别名“ EmpName”,并且对这两个名称进行选择都会返回该列中的数据。到目前为止和我在一起?
现在想象一下,该数据库有一个ADO.NET提供程序,他们已经为它编写了IDataReader实现,该实现考虑了列别名。
现在,dr.GetName(i)
(如乍得的答案中所使用的)只能返回一个字符串,因此它只必须返回列中的“别名” 之一。但是,GetOrdinal("EmpName")
可以使用此提供程序的字段的内部实现来检查每列的别名以查找所需的名称。
在这种假想的“别名列”情况下,try / GetOrdinal / catch方法将是确保您检查结果集中列名的每个变体的唯一方法。
lim弱?当然。但是值得一想。老实说,我宁愿在IDataRecord上使用“官方” HasColumn方法。
在一行中,在DataReader检索之后使用此命令:
var fieldNames = Enumerable.Range(0, dr.FieldCount).Select(i => dr.GetName(i)).ToArray();
然后,
if (fieldNames.Contains("myField"))
{
var myFieldValue = dr["myField"];
...
编辑
不需要加载架构的高效得多的一线工具:
var exists = Enumerable.Range(0, dr.FieldCount).Any(i => string.Equals(dr.GetName(i), fieldName, StringComparison.OrdinalIgnoreCase));
这是Jasmin的想法的工作示例:
var cols = r.GetSchemaTable().Rows.Cast<DataRow>().Select
(row => row["ColumnName"] as string).ToList();
if (cols.Contains("the column name"))
{
}
这对我有用:
bool hasColumnName = reader.GetSchemaTable().AsEnumerable().Any(c => c["ColumnName"] == "YOUR_COLUMN_NAME");
以下内容很简单,对我有用:
bool hasMyColumn = (reader.GetSchemaTable().Select("ColumnName = 'MyColumnName'").Count() == 1);
如果您读了这个问题,Michael会问的是DataReader,而不是DataRecord。正确放置对象。
r.GetSchemaTable().Columns.Contains(field)
在DataRecord上使用确实可以,但是它会返回BS列(请参见下面的屏幕截图。)
若要查看数据列是否存在并且在DataReader中包含数据,请使用以下扩展:
public static class DataReaderExtensions
{
/// <summary>
/// Checks if a column's value is DBNull
/// </summary>
/// <param name="dataReader">The data reader</param>
/// <param name="columnName">The column name</param>
/// <returns>A bool indicating if the column's value is DBNull</returns>
public static bool IsDBNull(this IDataReader dataReader, string columnName)
{
return dataReader[columnName] == DBNull.Value;
}
/// <summary>
/// Checks if a column exists in a data reader
/// </summary>
/// <param name="dataReader">The data reader</param>
/// <param name="columnName">The column name</param>
/// <returns>A bool indicating the column exists</returns>
public static bool ContainsColumn(this IDataReader dataReader, string columnName)
{
/// See: http://stackoverflow.com/questions/373230/check-for-column-name-in-a-sqldatareader-object/7248381#7248381
try
{
return dataReader.GetOrdinal(columnName) >= 0;
}
catch (IndexOutOfRangeException)
{
return false;
}
}
}
用法:
public static bool CanCreate(SqlDataReader dataReader)
{
return dataReader.ContainsColumn("RoleTemplateId")
&& !dataReader.IsDBNull("RoleTemplateId");
}
调用r.GetSchemaTable().Columns
DataReader会返回BS列:
IDataReader
实施IDataRecord
。它们是同一对象的不同接口-就像ICollection<T>
并且IEnumerable<T>
是List<T>
。 IDataReader
允许前进到下一条记录,而IDataRecord
允许从当前记录中读取。此答案中使用的方法全部来自IDataRecord
接口。请参阅stackoverflow.com/a/1357743/221708,以获取有关为什么IDataRecord
最好将参数声明为的解释。
r.GetSchemaTable().Columns
对这个问题绝对错误的答案。
我为Visual Basic用户写的:
Protected Function HasColumnAndValue(ByRef reader As IDataReader, ByVal columnName As String) As Boolean
For i As Integer = 0 To reader.FieldCount - 1
If reader.GetName(i).Equals(columnName) Then
Return Not IsDBNull(reader(columnName))
End If
Next
Return False
End Function
我认为这更强大,用法是:
If HasColumnAndValue(reader, "ID_USER") Then
Me.UserID = reader.GetDecimal(reader.GetOrdinal("ID_USER")).ToString()
End If
这里是Jasmine的解决方案中的一行...(另外,简单!):
reader.GetSchemaTable().Select("ColumnName='MyCol'").Length > 0;
TLDR:
关于性能和不良做法的说法有很多答案,因此我在这里进行澄清。
异常路由对于返回的列数较高的对象更快,循环路由对于较少的列数更快,并且交叉点在11列左右。滚动到底部以查看图形和测试代码。
完整答案:
某些最佳答案的代码有效,但基于对逻辑中异常处理的接受及其相关的性能,这里对于“更好”的答案存在潜在的争议。
为了澄清这一点,我认为关于CATCHING异常没有太多指导。Microsoft确实有一些有关THROWING异常的指导。他们在那里声明:
如有可能,请勿在正常的控制流程中使用例外。
首先要注意的是宽大的“如果可能的话”。更重要的是,描述提供了以下上下文:
framework designers should design APIs so users can write code that does not throw exceptions
这意味着如果您正在编写可能会被其他人使用的API,请让他们能够在没有try / catch的情况下导航异常。例如,为TryParse提供引发异常的Parse方法。 这无处说明您不应该捕获异常。
此外,正如另一个用户指出的那样,渔获物始终允许按类型进行过滤,而最近又允许通过 when子句。如果我们不应该使用它们,这似乎是对语言功能的浪费。
可以说,抛出异常会产生一些开销,并且该开销可能会在沉重的循环中影响性能。但是,也可以说,在“连接的应用程序”中,异常的代价将可以忽略不计。十年前对实际成本进行了调查: https //stackoverflow.com/a/891230/852208 换句话说,连接和查询数据库的成本可能会使抛出异常的成本相形见war。
除此之外,我想确定哪种方法真正更快。不出所料,没有具体答案。
随着列数的存在,任何在列上循环的代码都会变慢。也可以说,依赖于查询失败的速率,依赖于异常的任何代码都会变慢。
结合查德·格兰特(Chad Grant)和马特·汉密尔顿(Matt Hamilton)的答案,我同时使用了多达20列和高达50%的错误率的两种方法(OP表示他在不同的过程之间使用了这两项测试,因此我假设只有两种) 。
之字形是每个列计数内的故障率(未找到列)。
对于较窄的结果集,循环是一个不错的选择。但是,GetOrdinal / Exception方法对列数的敏感度并不高,并且开始在11列左右的性能上胜过循环方法。
就是说,我并没有真正的优先级性能,因为在整个应用程序中,平均返回的11列数听起来很合理。无论哪种情况,我们在这里谈论的都是毫秒。
但是,从代码简单性和别名支持的角度来看,我可能会选择GetOrdinal路由。
这是linqpad形式的测试。随意使用自己的方法重新发布:
void Main()
{
var loopResults = new List<Results>();
var exceptionResults = new List<Results>();
var totalRuns = 10000;
for (var colCount = 1; colCount < 20; colCount++)
{
using (var conn = new SqlConnection(@"Data Source=(localdb)\MSSQLLocalDb;Initial Catalog=master;Integrated Security=True;"))
{
conn.Open();
//create a dummy table where we can control the total columns
var columns = String.Join(",",
(new int[colCount]).Select((item, i) => $"'{i}' as col{i}")
);
var sql = $"select {columns} into #dummyTable";
var cmd = new SqlCommand(sql,conn);
cmd.ExecuteNonQuery();
var cmd2 = new SqlCommand("select * from #dummyTable", conn);
var reader = cmd2.ExecuteReader();
reader.Read();
Func<Func<IDataRecord, String, Boolean>, List<Results>> test = funcToTest =>
{
var results = new List<Results>();
Random r = new Random();
for (var faultRate = 0.1; faultRate <= 0.5; faultRate += 0.1)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var faultCount=0;
for (var testRun = 0; testRun < totalRuns; testRun++)
{
if (r.NextDouble() <= faultRate)
{
faultCount++;
if(funcToTest(reader, "colDNE"))
throw new ApplicationException("Should have thrown false");
}
else
{
for (var col = 0; col < colCount; col++)
{
if(!funcToTest(reader, $"col{col}"))
throw new ApplicationException("Should have thrown true");
}
}
}
stopwatch.Stop();
results.Add(new UserQuery.Results{
ColumnCount = colCount,
TargetNotFoundRate = faultRate,
NotFoundRate = faultCount * 1.0f / totalRuns,
TotalTime=stopwatch.Elapsed
});
}
return results;
};
loopResults.AddRange(test(HasColumnLoop));
exceptionResults.AddRange(test(HasColumnException));
}
}
"Loop".Dump();
loopResults.Dump();
"Exception".Dump();
exceptionResults.Dump();
var combinedResults = loopResults.Join(exceptionResults,l => l.ResultKey, e=> e.ResultKey, (l, e) => new{ResultKey = l.ResultKey, LoopResult=l.TotalTime, ExceptionResult=e.TotalTime});
combinedResults.Dump();
combinedResults
.Chart(r => r.ResultKey, r => r.LoopResult.Milliseconds * 1.0 / totalRuns, LINQPad.Util.SeriesType.Line)
.AddYSeries(r => r.ExceptionResult.Milliseconds * 1.0 / totalRuns, LINQPad.Util.SeriesType.Line)
.Dump();
}
public static bool HasColumnLoop(IDataRecord dr, string columnName)
{
for (int i = 0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
public static bool HasColumnException(IDataRecord r, string columnName)
{
try
{
return r.GetOrdinal(columnName) >= 0;
}
catch (IndexOutOfRangeException)
{
return false;
}
}
public class Results
{
public double NotFoundRate { get; set; }
public double TargetNotFoundRate { get; set; }
public int ColumnCount { get; set; }
public double ResultKey {get => ColumnCount + TargetNotFoundRate;}
public TimeSpan TotalTime { get; set; }
}
此代码纠正了Levitikon的代码所带来的问题:(改编自:[1]:http : //msdn.microsoft.com/zh-cn/library/system.data.datatablereader.getschematable.aspx)
public List<string> GetColumnNames(SqlDataReader r)
{
List<string> ColumnNames = new List<string>();
DataTable schemaTable = r.GetSchemaTable();
DataRow row = schemaTable.Rows[0];
foreach (DataColumn col in schemaTable.Columns)
{
if (col.ColumnName == "ColumnName")
{
ColumnNames.Add(row[col.Ordinal].ToString());
break;
}
}
return ColumnNames;
}
之所以要获取所有这些无用的列名而不是从表中获取列名,是因为您正在获取模式列的名称(即模式表的列名)
注意:这似乎只返回第一列的名称...
编辑:更正后的代码将返回所有列的名称,但是您不能使用SqlDataReader来执行此操作
public List<string> ExecuteColumnNamesReader(string command, List<SqlParameter> Params)
{
List<string> ColumnNames = new List<string>();
SqlDataAdapter da = new SqlDataAdapter();
string connection = ""; // your sql connection string
SqlCommand sqlComm = new SqlCommand(command, connection);
foreach (SqlParameter p in Params) { sqlComm.Parameters.Add(p); }
da.SelectCommand = sqlComm;
DataTable dt = new DataTable();
da.Fill(dt);
DataRow row = dt.Rows[0];
for (int ordinal = 0; ordinal < dt.Columns.Count; ordinal++)
{
string column_name = dt.Columns[ordinal].ColumnName;
ColumnNames.Add(column_name);
}
return ColumnNames; // you can then call .Contains("name") on the returned collection
}
return r.GetSchemaTable().Rows.Cast<DataRow>().Select(x => (string)x["ColumnName"]).ToList();
:)
为了保持代码的健壮和整洁,请使用单个扩展功能,如下所示:
Public Module Extensions
<Extension()>
Public Function HasColumn(r As SqlDataReader, columnName As String) As Boolean
Return If(String.IsNullOrEmpty(columnName) OrElse r.FieldCount = 0, False, Enumerable.Range(0, r.FieldCount).Select(Function(i) r.GetName(i)).Contains(columnName, StringComparer.OrdinalIgnoreCase))
End Function
End Module
我也没有GetSchemaTable
去上班,直到我发现这种方式。
基本上我是这样做的:
Dim myView As DataView = dr.GetSchemaTable().DefaultView
myView.RowFilter = "ColumnName = 'ColumnToBeChecked'"
If myView.Count > 0 AndAlso dr.GetOrdinal("ColumnToBeChecked") <> -1 Then
obj.ColumnToBeChecked = ColumnFromDb(dr, "ColumnToBeChecked")
End If
public static bool DataViewColumnExists(DataView dv, string columnName)
{
return DataTableColumnExists(dv.Table, columnName);
}
public static bool DataTableColumnExists(DataTable dt, string columnName)
{
string DebugTrace = "Utils::DataTableColumnExists(" + dt.ToString() + ")";
try
{
return dt.Columns.Contains(columnName);
}
catch (Exception ex)
{
throw new MyExceptionHandler(ex, DebugTrace);
}
}
Columns.Contains
顺便说一句,不区分大小写。
在您的特定情况下(除1之外,所有过程都具有相同的列,而另外1列具有附加的1列),检查阅读器会更好更快。FieldCount属性可以区分它们。
const int NormalColCount=.....
if(reader.FieldCount > NormalColCount)
{
// Do something special
}
我知道这是一个旧帖子,但我决定在相同情况下回答以帮助其他人。您也可以(出于性能原因)将此解决方案与解决方案迭代解决方案混合使用。
我的数据访问类需要向后兼容,因此我可能正在尝试访问数据库中尚不存在的发行版中的列。我们返回了一些相当大的数据集,所以我不喜欢必须为每个属性迭代DataReader列集合的扩展方法。
我有一个实用程序类,它创建一个列的私有列表,然后有一个通用方法尝试根据列名和输出参数类型来解析一个值。
private List<string> _lstString;
public void GetValueByParameter<T>(IDataReader dr, string parameterName, out T returnValue)
{
returnValue = default(T);
if (!_lstString.Contains(parameterName))
{
Logger.Instance.LogVerbose(this, "missing parameter: " + parameterName);
return;
}
try
{
if (dr[parameterName] != null && [parameterName] != DBNull.Value)
returnValue = (T)dr[parameterName];
}
catch (Exception ex)
{
Logger.Instance.LogException(this, ex);
}
}
/// <summary>
/// Reset the global list of columns to reflect the fields in the IDataReader
/// </summary>
/// <param name="dr">The IDataReader being acted upon</param>
/// <param name="NextResult">Advances IDataReader to next result</param>
public void ResetSchemaTable(IDataReader dr, bool nextResult)
{
if (nextResult)
dr.NextResult();
_lstString = new List<string>();
using (DataTable dataTableSchema = dr.GetSchemaTable())
{
if (dataTableSchema != null)
{
foreach (DataRow row in dataTableSchema.Rows)
{
_lstString.Add(row[dataTableSchema.Columns["ColumnName"]].ToString());
}
}
}
}
然后我可以像这样调用我的代码
using (var dr = ExecuteReader(databaseCommand))
{
int? outInt;
string outString;
Utility.ResetSchemaTable(dr, false);
while (dr.Read())
{
Utility.GetValueByParameter(dr, "SomeColumn", out outInt);
if (outInt.HasValue) myIntField = outInt.Value;
}
Utility.ResetSchemaTable(dr, true);
while (dr.Read())
{
Utility.GetValueByParameter(dr, "AnotherColumn", out outString);
if (!string.IsNullOrEmpty(outString)) myIntField = outString;
}
}
整个问题的关键在这里:
if (-1 == index) {
throw ADP.IndexOutOfRange(fieldName);
}
如果删除了参考的三行(当前是第72、73和74行),则可以轻松地进行检查-1
以确定该列是否不存在。
确保本机性能的唯一方法是使用Reflection
基于基础的实现,如下所示:
用途:
using System;
using System.Data;
using System.Reflection;
using System.Data.SqlClient;
using System.Linq;
using System.Web.Compilation; // I'm not sure what the .NET Core equivalent to BuildManager.cs
基于反射的扩展方法:
/// Gets the column ordinal, given the name of the column.
/// </summary>
/// <param name="reader"></param>
/// <param name="name">The name of the column.</param>
/// <returns> The zero-based column ordinal. -1 if the column does not exist.</returns>
public static int GetOrdinalSoft(this SqlDataReader reader, string name)
{
try
{
// Note that "Statistics" will not be accounted for in this implemenation
// If you have SqlConnection.StatisticsEnabled set to true (the default is false), you probably don't want to use this method
// All of the following logic is inspired by the actual implementation of the framework:
// https://referencesource.microsoft.com/#System.Data/fx/src/data/System/Data/SqlClient/SqlDataReader.cs,d66096b6f57cac74
if (name == null)
throw new ArgumentNullException("fieldName");
Type sqlDataReaderType = typeof(SqlDataReader);
object fieldNameLookup = sqlDataReaderType.GetField("_fieldNameLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reader);
Type fieldNameLookupType;
if (fieldNameLookup == null)
{
MethodInfo checkMetaDataIsReady = sqlDataReaderType.GetRuntimeMethods().First(x => x.Name == "CheckMetaDataIsReady" && x.GetParameters().Length == 0);
checkMetaDataIsReady.Invoke(reader, null);
fieldNameLookupType = BuildManager.GetType("System.Data.ProviderBase.FieldNameLookup", true, false);
ConstructorInfo ctor = fieldNameLookupType.GetConstructor(new[] { typeof(SqlDataReader), typeof(int) });
fieldNameLookup = ctor.Invoke(new object[] { reader, sqlDataReaderType.GetField("_defaultLCID", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reader) });
}
else
fieldNameLookupType = fieldNameLookup.GetType();
MethodInfo indexOf = fieldNameLookupType.GetMethod("IndexOf", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);
return (int)indexOf.Invoke(fieldNameLookup, new object[] { name });
}
catch
{
// .NET Implemenation might have changed, revert back to the classic solution.
if (reader.FieldCount > 11) // Performance observation by b_levitt
{
try
{
return reader.GetOrdinal(name);
}
catch
{
return -1;
}
}
else
{
var exists = Enumerable.Range(0, reader.FieldCount).Any(i => string.Equals(reader.GetName(i), name, StringComparison.OrdinalIgnoreCase));
if (exists)
return reader.GetOrdinal(name);
else
return -1;
}
}
}
如果您想要列的列表并且不想获取异常,也可以在DataReader上调用GetSchemaTable()。
怎么样
if (dr.GetSchemaTable().Columns.Contains("accounttype"))
do something
else
do something
它可能不会像循环中那样高效
dr.GetSchemaTable().Columns
包含的东西-不是您要的东西。
尽管没有公开的方法,但是内部类System.Data.ProviderBase.FieldNameLookup
中确实存在一个方法SqlDataReader
依赖于。
为了访问它并获得本机性能,必须使用ILGenerator在运行时创建一个方法。下面的代码会给你直接访问int IndexOf(string fieldName)
的System.Data.ProviderBase.FieldNameLookup
类以及执行记账是SqlDataReader.GetOrdinal()
这样做,有没有副作用。生成的代码会镜像现有代码,SqlDataReader.GetOrdinal()
只是它调用FieldNameLookup.IndexOf()
而不是FieldNameLookup.GetOrdinal()
。该GetOrdinal()
方法调用该IndexOf()
函数,如果-1
返回则抛出异常,因此我们绕过该行为。
using System;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Reflection.Emit;
public static class SqlDataReaderExtensions {
private delegate int IndexOfDelegate(SqlDataReader reader, string name);
private static IndexOfDelegate IndexOf;
public static int GetColumnIndex(this SqlDataReader reader, string name) {
return name == null ? -1 : IndexOf(reader, name);
}
public static bool ContainsColumn(this SqlDataReader reader, string name) {
return name != null && IndexOf(reader, name) >= 0;
}
static SqlDataReaderExtensions() {
Type typeSqlDataReader = typeof(SqlDataReader);
Type typeSqlStatistics = typeSqlDataReader.Assembly.GetType("System.Data.SqlClient.SqlStatistics", true);
Type typeFieldNameLookup = typeSqlDataReader.Assembly.GetType("System.Data.ProviderBase.FieldNameLookup", true);
BindingFlags staticflags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Static;
BindingFlags instflags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance;
DynamicMethod dynmethod = new DynamicMethod("SqlDataReader_IndexOf", typeof(int), new Type[2]{ typeSqlDataReader, typeof(string) }, true);
ILGenerator gen = dynmethod.GetILGenerator();
gen.DeclareLocal(typeSqlStatistics);
gen.DeclareLocal(typeof(int));
// SqlStatistics statistics = (SqlStatistics) null;
gen.Emit(OpCodes.Ldnull);
gen.Emit(OpCodes.Stloc_0);
// try {
gen.BeginExceptionBlock();
// statistics = SqlStatistics.StartTimer(this.Statistics);
gen.Emit(OpCodes.Ldarg_0); //this
gen.Emit(OpCodes.Call, typeSqlDataReader.GetProperty("Statistics", instflags | BindingFlags.GetProperty, null, typeSqlStatistics, Type.EmptyTypes, null).GetMethod);
gen.Emit(OpCodes.Call, typeSqlStatistics.GetMethod("StartTimer", staticflags | BindingFlags.InvokeMethod, null, new Type[] { typeSqlStatistics }, null));
gen.Emit(OpCodes.Stloc_0); //statistics
// if(this._fieldNameLookup == null) {
Label branchTarget = gen.DefineLabel();
gen.Emit(OpCodes.Ldarg_0); //this
gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.GetField));
gen.Emit(OpCodes.Brtrue_S, branchTarget);
// this.CheckMetaDataIsReady();
gen.Emit(OpCodes.Ldarg_0); //this
gen.Emit(OpCodes.Call, typeSqlDataReader.GetMethod("CheckMetaDataIsReady", instflags | BindingFlags.InvokeMethod, null, Type.EmptyTypes, null));
// this._fieldNameLookup = new FieldNameLookup((IDataRecord)this, this._defaultLCID);
gen.Emit(OpCodes.Ldarg_0); //this
gen.Emit(OpCodes.Ldarg_0); //this
gen.Emit(OpCodes.Ldarg_0); //this
gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_defaultLCID", instflags | BindingFlags.GetField));
gen.Emit(OpCodes.Newobj, typeFieldNameLookup.GetConstructor(instflags, null, new Type[] { typeof(IDataReader), typeof(int) }, null));
gen.Emit(OpCodes.Stfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.SetField));
// }
gen.MarkLabel(branchTarget);
gen.Emit(OpCodes.Ldarg_0); //this
gen.Emit(OpCodes.Ldfld, typeSqlDataReader.GetField("_fieldNameLookup", instflags | BindingFlags.GetField));
gen.Emit(OpCodes.Ldarg_1); //name
gen.Emit(OpCodes.Call, typeFieldNameLookup.GetMethod("IndexOf", instflags | BindingFlags.InvokeMethod, null, new Type[] { typeof(string) }, null));
gen.Emit(OpCodes.Stloc_1); //int output
Label leaveProtectedRegion = gen.DefineLabel();
gen.Emit(OpCodes.Leave_S, leaveProtectedRegion);
// } finally {
gen.BeginFaultBlock();
// SqlStatistics.StopTimer(statistics);
gen.Emit(OpCodes.Ldloc_0); //statistics
gen.Emit(OpCodes.Call, typeSqlStatistics.GetMethod("StopTimer", staticflags | BindingFlags.InvokeMethod, null, new Type[] { typeSqlStatistics }, null));
// }
gen.EndExceptionBlock();
gen.MarkLabel(leaveProtectedRegion);
gen.Emit(OpCodes.Ldloc_1);
gen.Emit(OpCodes.Ret);
IndexOf = (IndexOfDelegate)dynmethod.CreateDelegate(typeof(IndexOfDelegate));
}
}
if(Enumerable.Range(0,reader.FieldCount).Select(reader.GetName).Contains("columName"))
{
employee.EmployeeId= Utility.ConvertReaderToLong(reader["EmployeeId"]);
}
您可以从此处获取更多详细信息:可以从SqlDataReader获取列名吗?