2010-06-04 14 views
6

Tengo un código de capa de acceso a datos que llama a un proceso almacenado y devuelve valores escalares de varios tipos de datos. La sintaxis es ExecuteDecimal, ExecuteString, etc. Yo quiero que sea Execute<string> o Execute<decimal>¿Cómo hago para que los genéricos funcionen con valores devueltos que requieren un casting cuidadoso?

Intento esta aplicación y no puedo compilar, a menos que yo estoy haciendo la fundición a "valor (T)", si intento verifica el tipo y llama a un método para hacer el casting, sin tanta suerte.

pregunta ACTUALIZADA ¿Por qué tengo que convertir a objeto antes de convertir a T?

código actualizado

internal T Execute<T>(string storedProcName, Hashtable parameters) 
{ 
     //Next lines do compile (thanks to suggestions from answers!) 
     if (typeof(T) == typeof(string)) 
      return (T) (object) ExecuteScalar(storedProcName, parameters).ToString(); 
     else if (typeof(T) == typeof(int)) 
      return (T)(object) Convert.ToInt32(ExecuteScalar(storedProcName, parameters)); 
     //Next line compiles, but not all things boxed in an object can 
     //be converted straight to type T (esp db return values that might contain DbNull.Value, etc) 
     return (T)ExecuteScalar(storedProcName, parameters); 
} 
+0

hey, estoy realmente preocupado. las primeras tres respuestas (con los votos más altos) son con errores o están hinchadas con código innecesario. – Andrey

+0

@Andrey, bienvenido a SO = (Estoy decepcionado de no aprender sobre 'casting cuidadoso'. Estaba tan emocionado cuando leí el título. =) – Marc

Respuesta

8

Prueba esto:

var result = ExecuteScalar(storedProcName, parameters); 
if(Convert.IsDBNull(result)) 
    return default(T) 
if(result is T) // just unbox 
    return (T)result; 
else   // convert 
    return (T)Convert.ChangeType(result, typeof(T)); 

Actualizado: DBNull fijo manejo

+0

Interesante, Parece que ChangeType solo admite cosas que admiten IConvertable. Nunca había visto esa técnica antes. ¡Gracias! – MatthewMartin

+1

@MatthewMartin todos los tipos primitivos lo admiten. Pero este método no es bueno porque max no verificó DBNull – Andrey

+0

¿Quién diablos lo votó? arroja una excepción en DBNull – Andrey

1
typeof(T) == typeof(string) 

y para la comprobación de valor nulo en contra DBNull.Value

método global:

internal T Execute<T>(string storedProcName, Hashtable parameters) 
{ 
     object res = ExecuteScalar(storedProcName, parameters); 
     if (Convert.IsDBNull(res)) 
     return default(T); //or handle somehow 
     return (T)Convert.ChangeType(res, typeof(T)); 
} 
+0

@Andrey - eso no compilará. – dcp

+0

¡No lo has verificado! Pero gracias de todos modos, me puso en el camino correcto y creo que lo entendí. He actualizado mi pregunta con el nuevo código. – MatthewMartin

+0

Ah se ve mejor – MatthewMartin

1

probar el 'como' palabra clave

object o = ExecuteScalar(storedProcName, parameters); 
string s; 
int i; 
// .. more 

if ((s = o as string) != null) 
{ 
    return s; 
} 
if ((i = o as int?) != null) // can't use as for value types, so use nullable 
{ 
    return Convert.ToInt32(o); 
} 
return o as T; 
+1

Convert.ChangeType hace todo por usted.y no busca DBNull – Andrey

+2

No. La palabra clave 'como' no es válida para los tipos de valores. –

+0

Gracias Joel, tienes razón. Todo mejor ahora – paquetp

0

Tal vez su función en lugar podría ser alterado para permitir la función de conversión de objeto que se aprobó en:

internal T Execute<T>(string storedProcName, Hashtable parameters, Func<object, T> resultConverter) 
{ 
} 

Luego puede crear sobrecargas para las que conoce:

internal string ExecuteForString(string storedProcName, Hashtable parameters) 
{ 
    return Execute(storedProcName, parameters, (o) => o.ToString()); 
} 

internal int ExecuteForInt(string storedProcName, Hashtable parameters) 
{ 
    return Execute(storedProcName, parameters, Convert.ToInt32); 
} 

En el caso de los cheques DBNull, podría volver ya sea default(T) o se puede añadir otra sobrecarga de pasar en un valor por defecto si no se devuelve DBNull - por ejemplo, en el caso de un int, es mejor recuperar -1 en lugar de 0.

+0

Desafortunadamente no se puede sobrecargar en los tipos de devolución, los tipos de argumentos deben diferir en tipo y/o número. –

+0

Interesante Nunca he visto el valor por defecto (T) de T antes de pensar que usaré eso. Elimine la parte que no se compilará para poder votar su respuesta. – MatthewMartin

+0

Ha cambiado el nombre de las funciones para evitar problemas de compilación, ya que creo que es preferible en lugar de terminar con un caso de un tipo que no puede resolver para la persona que llama ... – Reddog

Cuestiones relacionadas