valores valor validar tipo tienen tener solo significado ser que puede propiedad objeto nulo método los llamar lectura fecha este distinto debe datos convertir con acepta c# .net generics

c# - validar - ¿Puede un Método genérico manejar los tipos de Referencia y Valor Nullable?



string nullable c# (8)

Esto funciona:

public static T Get<T>( this IDataRecord dr, int ordinal) { T nullValue = default(T); return dr.IsDBNull(ordinal) ? nullValue : (T) dr.GetValue(ordinal); } public void Code(params string[] args) { IDataRecord dr= null; int? a = Get<int?>(dr, 1); string b = Get<string>(dr, 2); }

Tengo una serie de métodos de extensión para ayudar con la comprobación nula de objetos IDataRecord, que actualmente estoy implementando así:

public static int? GetNullableInt32(this IDataRecord dr, int ordinal) { int? nullInt = null; return dr.IsDBNull(ordinal) ? nullInt : dr.GetInt32(ordinal); } public static int? GetNullableInt32(this IDataRecord dr, string fieldname) { int ordinal = dr.GetOrdinal(fieldname); return dr.GetNullableInt32(ordinal); }

y así sucesivamente, para cada tipo que necesito tratar.

Me gustaría volver a implementar esto como un método genérico, en parte para reducir la redundancia y en parte para aprender a escribir métodos genéricos en general.

He escrito esto:

public static Nullable<T> GetNullable<T>(this IDataRecord dr, int ordinal) { Nullable<T> nullValue = null; return dr.IsDBNull(ordinal) ? nullValue : (Nullable<T>) dr.GetValue(ordinal); }

que funciona siempre que T sea un tipo de valor, pero si T es un tipo de referencia, no lo hará.

Este método debería devolver un tipo Nullable si T es un tipo de valor y, de lo contrario, (T) es el predeterminado. ¿Cómo implementaría este comportamiento?


La estructura Nullable es solo para tipos de valores, porque los tipos de referencia son anulables de todos modos ...


Lo hago de esta manera:

DataRow record = GetSomeRecord(); int? someNumber = record[15] as int? Guid? someUID = record["MyPrimaryKey"] as Guid?; string someText = GetSomeText(); record["Description"] = someText.ToDbString(); // ........ public static class StringExtensionHelper { public static object ToDbString( this string text ) { object ret = null != text ? text : DBNull.Value return ret; } }

EDITAR: Puede (o debería) tener métodos de extensión "ToDbInt32, ToDbBool, etc ..." para otros tipos primitivos, por supuesto.

EDIT 2: También puede extender el "objeto" de la clase base con "ToDbValue".

public static class StringExtensionHelper { public static object ToDbValue( this object value ) { object ret = object.ReferenceEquals( value, null ) ? (object)DBNull.Value : value; return ret; } }


No puedes hacerlo con un método, pero lo haces con tres:

public static T GetData<T>(this IDataReader reader, Func<int, T> getFunc, int index) { if (!reader.IsClosed) { return getFunc(index); } throw new ArgumentException("Reader is closed.", "reader"); } public static T GetDataNullableRef<T>(this IDataReader reader, Func<int, T> getFunc, int index) where T : class { if (!reader.IsClosed) { return reader.IsDBNull(index) ? null : getFunc(index); } throw new ArgumentException("Reader is closed.", "reader"); } public static T? GetDataNullableValue<T>(this IDataReader reader, Func<int, T> getFunc, int index) where T : struct { if (!reader.IsClosed) { return reader.IsDBNull(index) ? (T?)null : getFunc(index); } throw new ArgumentException("Reader is closed.", "reader"); }

Entonces para usarlo harías:

private static Whatever CreateObject(IDataReader reader) { Int32? id = reader.GetDataNullableValue<Int32>(reader.GetInt32, 0); string name = reader.GetDataNullableRef<string>(reader.GetString, 1); Int32 x = reader.GetData<Int32>(reader.GetInt32, 2); }


Puedes declarar tu método así:

public static T GetNullable<T>(this IDataRecord dr, int ordinal) { return dr.IsDBNull(ordinal) ? default(T) : (T) dr.GetValue(ordinal); }

De esta forma, si T es un int anulable o cualquier otro tipo de valor que admite valores NULL, de hecho devolverá null. Si se trata de un tipo de datos normal, simplemente devolverá el valor predeterminado para ese tipo.


public static T Get<T>(this IDataRecord rec, Func<int, T> GetValue, int ordinal) { return rec.IsDBNull(ordinal) ? default(T) : GetValue(ordinal); }

o más rendimiento

public static T Get<T>(this IDataRecord rec, Func<IDataRecord, int, T> GetValue, int ordinal) { return rec.IsDBNull(ordinal) ? default(T) : GetValue(rec, ordinal); } public static Func<IDataRecord, int, int> GetInt32 = (rec, i) => rec.GetInt32(i); public static Func<IDataRecord, int, bool> GetBool = (rec, i) => rec.GetBoolean(i); public static Func<IDataRecord, int, string> GetString = (rec, i) => rec.GetString(i);

y úsalo así

rec.Get(GetString, index); rec.Get(GetInt32, index);


No puedo entender por qué la necesidad de complicar demasiado todo este proceso. ¿Por qué no mantenerlo simple y agradable y usar las siguientes líneas de código:

Para los tipos de valor donde null es válido use int? iNullable = dr[ordinal] as int?; int? iNullable = dr[ordinal] as int?; .

Para los tipos de valor donde null no es válido, use int iNonNullable = dr[ordinal] as int? ?? default(int); int iNonNullable = dr[ordinal] as int? ?? default(int); .

Para los tipos de referencia use string sValue = dr[ordinal] as string; .

Para cualquiera que piense que el código no funcionará y que dr[ordinal] arrojará una excepción para DBNull aquí, hay un método de ejemplo que una vez que se le da una cadena de conexión válida, probará el concepto.

private void Test() { int? iTestA; int? iTestB; int iTestC; string sTestA; string sTestB; //Create connection using (SqlConnection oConnection = new SqlConnection(@"")) { //Open connection oConnection.Open(); //Create command using (SqlCommand oCommand = oConnection.CreateCommand()) { //Set command text oCommand.CommandText = "SELECT null, 1, null, null, ''1''"; //Create reader using (SqlDataReader oReader = oCommand.ExecuteReader()) { //Read the data oReader.Read(); //Set the values iTestA = oReader[0] as int?; iTestB = oReader[1] as int?; iTestC = oReader[2] as int? ?? -1; sTestA = oReader[3] as string; sTestB = oReader[4] as string; } } } }


No creo que puedas implementar esto con una sola función. Si C # admite la sobrecarga en función del tipo de devolución, es posible que pueda hacerlo, pero incluso así recomendaría que no lo haga.

Debería poder lograr lo mismo al no usar tipos de datos que aceptan nulos y devolver un valor real o nulo, como lo sugiere BFree.