| File: System\Data\DataRowExtensions.cs | Web Access |
| Project: src\runtime\src\libraries\System.Data.Common\src\System.Data.Common.csproj (System.Data.Common) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace System.Data { /// <summary> /// This static class defines the DataRow extension methods. /// </summary> public static class DataRowExtensions { /// <summary> /// This method provides access to the values in each of the columns in a given row. /// This method makes casts unnecessary when accessing columns. /// Additionally, Field supports nullable types and maps automatically between DBNull and /// Nullable when the generic type is nullable. /// </summary> /// <param name="row">The input DataRow</param> /// <param name="columnName">The input column name specifying which row value to retrieve.</param> /// <returns>The DataRow value for the column specified.</returns> public static T? Field<T>(this DataRow row, string columnName) { DataSetUtil.CheckArgumentNull(row, nameof(row)); return UnboxT<T>.s_unbox(row[columnName]); } /// <summary> /// This method provides access to the values in each of the columns in a given row. /// This method makes casts unnecessary when accessing columns. /// Additionally, Field supports nullable types and maps automatically between DBNull and /// Nullable when the generic type is nullable. /// </summary> /// <param name="row">The input DataRow</param> /// <param name="column">The input DataColumn specifying which row value to retrieve.</param> /// <returns>The DataRow value for the column specified.</returns> public static T? Field<T>(this DataRow row, DataColumn column) { DataSetUtil.CheckArgumentNull(row, nameof(row)); return UnboxT<T>.s_unbox(row[column]); } /// <summary> /// This method provides access to the values in each of the columns in a given row. /// This method makes casts unnecessary when accessing columns. /// Additionally, Field supports nullable types and maps automatically between DBNull and /// Nullable when the generic type is nullable. /// </summary> /// <param name="row">The input DataRow</param> /// <param name="columnIndex">The input ordinal specifying which row value to retrieve.</param> /// <returns>The DataRow value for the column specified.</returns> public static T? Field<T>(this DataRow row, int columnIndex) { DataSetUtil.CheckArgumentNull(row, nameof(row)); return UnboxT<T>.s_unbox(row[columnIndex]); } /// <summary> /// This method provides access to the values in each of the columns in a given row. /// This method makes casts unnecessary when accessing columns. /// Additionally, Field supports nullable types and maps automatically between DBNull and /// Nullable when the generic type is nullable. /// </summary> /// <param name="row">The input DataRow</param> /// <param name="columnIndex">The input ordinal specifying which row value to retrieve.</param> /// <param name="version">The DataRow version for which row value to retrieve.</param> /// <returns>The DataRow value for the column specified.</returns> public static T? Field<T>(this DataRow row, int columnIndex, DataRowVersion version) { DataSetUtil.CheckArgumentNull(row, nameof(row)); return UnboxT<T>.s_unbox(row[columnIndex, version]); } /// <summary> /// This method provides access to the values in each of the columns in a given row. /// This method makes casts unnecessary when accessing columns. /// Additionally, Field supports nullable types and maps automatically between DBNull and /// Nullable when the generic type is nullable. /// </summary> /// <param name="row">The input DataRow</param> /// <param name="columnName">The input column name specifying which row value to retrieve.</param> /// <param name="version">The DataRow version for which row value to retrieve.</param> /// <returns>The DataRow value for the column specified.</returns> public static T? Field<T>(this DataRow row, string columnName, DataRowVersion version) { DataSetUtil.CheckArgumentNull(row, nameof(row)); return UnboxT<T>.s_unbox(row[columnName, version]); } /// <summary> /// This method provides access to the values in each of the columns in a given row. /// This method makes casts unnecessary when accessing columns. /// Additionally, Field supports nullable types and maps automatically between DBNull and /// Nullable when the generic type is nullable. /// </summary> /// <param name="row">The input DataRow</param> /// <param name="column">The input DataColumn specifying which row value to retrieve.</param> /// <param name="version">The DataRow version for which row value to retrieve.</param> /// <returns>The DataRow value for the column specified.</returns> public static T? Field<T>(this DataRow row, DataColumn column, DataRowVersion version) { DataSetUtil.CheckArgumentNull(row, nameof(row)); return UnboxT<T>.s_unbox(row[column, version]); } /// <summary> /// This method sets a new value for the specified column for the DataRow it's called on. /// </summary> /// <param name="row">The input DataRow.</param> /// <param name="columnIndex">The input ordinal specifying which row value to set.</param> /// <param name="value">The new row value for the specified column.</param> public static void SetField<T>(this DataRow row, int columnIndex, T? value) { DataSetUtil.CheckArgumentNull(row, nameof(row)); row[columnIndex] = (object?)value ?? DBNull.Value; } /// <summary> /// This method sets a new value for the specified column for the DataRow it's called on. /// </summary> /// <param name="row">The input DataRow.</param> /// <param name="columnName">The input column name specifying which row value to retrieve.</param> /// <param name="value">The new row value for the specified column.</param> public static void SetField<T>(this DataRow row, string columnName, T? value) { DataSetUtil.CheckArgumentNull(row, nameof(row)); row[columnName] = (object?)value ?? DBNull.Value; } /// <summary> /// This method sets a new value for the specified column for the DataRow it's called on. /// </summary> /// <param name="row">The input DataRow.</param> /// <param name="column">The input DataColumn specifying which row value to retrieve.</param> /// <param name="value">The new row value for the specified column.</param> public static void SetField<T>(this DataRow row, DataColumn column, T? value) { DataSetUtil.CheckArgumentNull(row, nameof(row)); row[column] = (object?)value ?? DBNull.Value; } private static class UnboxT<T> { internal static readonly Func<object, T?> s_unbox = Create(); private static Func<object, T?> Create() { if (typeof(T).IsValueType && default(T) == null) { if (!RuntimeFeature.IsDynamicCodeSupported) return NullableFieldUsingReflection; return CreateWhenDynamicCodeSupported(); } return NonNullableField; [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2091:MakeGenericMethod", Justification = "'NullableField<TElem> where TElem : struct' implies 'TElem : new()'. Nullable does not make use of new() so it is safe." + "The warning is only issued when IsDynamicCodeSupported is true.")] static Func<object, T?> CreateWhenDynamicCodeSupported() { #pragma warning disable IL3050 // There is a path that is safe for AOT executed when IsDynamicCodeSupported is false. return typeof(UnboxT<T>) .GetMethod("NullableField", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)! .MakeGenericMethod(Nullable.GetUnderlyingType(typeof(T))!) .CreateDelegate<Func<object, T>>(); #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. } } private static T? NonNullableField(object value) { if (value == DBNull.Value) { if (default(T) is null) return default; throw DataSetUtil.InvalidCast(SR.Format(SR.DataSetLinq_NonNullableCast, typeof(T))); } return (T)value; } private static T? NullableFieldUsingReflection(object value) { if (value == DBNull.Value) return default; // Try regular cast first if (value is T t) return t; Type valueType = value.GetType(); Type nullableType = Nullable.GetUnderlyingType(typeof(T))!; // Convert does all sorts of conversions. We are only interested in conversions for enums. Type fromType = valueType.IsEnum ? Enum.GetUnderlyingType(valueType) : valueType; Type toType = nullableType.IsEnum ? Enum.GetUnderlyingType(nullableType) : nullableType; if (fromType == toType) value = nullableType.IsEnum ? Enum.ToObject(nullableType, value) : Convert.ChangeType(value, nullableType, null); return (T)value; } private static Nullable<TElem> NullableField<TElem>(object value) where TElem : struct => value == DBNull.Value ? default : new Nullable<TElem>((TElem)value); } } }