.NET: ¿Cómo se obtiene el tipo de objeto nulo?

Tengo un método con un parámetro de salida que intenta hacer una conversión de tipo. Básicamente:

public void GetParameterValue(out object destination) { object paramVal = "I want to return this. could be any type, not just string."; destination = null; // default out param to null destination = Convert.ChangeType(paramVal, destination.GetType()); } 

El problema es que generalmente alguien llamaría esto como:

 string output; GetParameterValue(output); 

Esto fracasará debido a:

 destination.GetType() 

el destino es nulo, por lo que no podemos llamar a .GetType() en él. Tampoco podemos llamar:

 typeof(destination) 

porque el destino es un nombre de variable, no un nombre de tipo.

Entonces, ¿hay alguna manera de obtener el tipo de un objeto que se establece en nulo? Pensaría que tendría que haber una manera de saber qué tipo es una ubicación de almacenamiento sin que se le asigne nada.


Solo para dar un poco más de información, estoy tratando de hacer un método de utilidad que capte los parámetros de salida de un procedimiento almacenado de Oracle. El problema es que DbParameter.Value es de tipo objeto.

Lo ideal sería que los desarrolladores hicieran algo como:

 string val = GetParameterValue("parameterName"); 

Lo notable es que no hay conversión de tipos. En la práctica, no conoces el lparam de “iguales”, así que fui con:

 string val; GetParameterValue("parameterName", out val); 

Y figurado dentro del método, sabría el tipo de destino de la variable de salida. Supongo que fue una mala suposición. Como alternativa, también escribí el método:

 public T GetParameterValue(string paramName) 

Entonces los desarrolladores pueden hacer:

 string val = GetParameterValue("parameterName"); 

Encuentro que la statement explícita de “cadena” es repetitiva, especialmente porque en la práctica, el destino es probablemente una propiedad del objeto y el tipo de datos del oracle podría cambiar (piense en ORM):

 MyObj.SomeProp = GetParameterValue("parameterName"); 

Pero nuevamente, si MyObj.SomeProp es nulo, esa llamada .GetType() falla. La máquina virtual tiene que saber el tipo de MyObj.SomeProp , incluso cuando es nulo, ¿verdad? o de lo contrario, ¿cómo captaría las excepciones de lanzamiento?


Para resolver parcialmente mi propio problema, puedo:

 MyObj.SomeProp = GetParameterValue("parameterName"); 

La idea general era no tener que utilizar explícitamente el Tipo en más de un lugar, de modo que si el tipo de datos cambia, solo tiene que cambiarse en el objeto de destino ( MyObj.SomeProp ) y en el DB. Tiene que haber una mejor manera…

Entonces, ¿hay alguna manera de obtener el tipo de un objeto que se establece en nulo? Pensaría que tendría que haber una manera de saber qué tipo es una ubicación de almacenamiento sin que se le asigne nada.

No necesariamente. Lo mejor que puedes decir es que es un object . Una referencia null no apunta a ninguna ubicación de almacenamiento, por lo que no hay metadatos a partir de los cuales pueda hacer esa determinación.

Lo mejor que puedes hacer es cambiarlo para que sea más genérico, como en:

 public void GetParameterValue(out T destination) { object paramVal = "Blah"; destination = default(T); destination = Convert.ChangeType(paramVal, typeof(T)); } 

El tipo de T puede inferirse, por lo que no debería necesitar dar un parámetro de tipo al método explícitamente.

Es posible si no te importa declarar tu método como genérico. Prueba esto.

 class Program { public static void GetParameterValue(out T destination) { Console.WriteLine("typeof(T)=" + typeof(T).Name); destination = default(T); } static void Main(string[] args) { string s; GetParameterValue(out s); int i; GetParameterValue(out i); } } 

El siguiente método de extensión devuelve el tipo de su parámetro tal como fue declarado , independientemente de su contenido:

 using System; namespace MyNamespace { public static class Extensions { ///  /// Gets the declared type of the specified object. ///  /// The type of the object. /// The object. ///  /// A  object representing type /// ; ie, the type of  /// as it was declared. Note that the contents of ///  are irrelevant; if  /// contains an object whose class is derived from /// , then  is /// returned, not the derived type. ///  public static Type GetDeclaredType( this T obj ) { return typeof( T ); } } } 

Como este es un método de extensión, su argumento puede ser una referencia nula, y todo lo siguiente funciona bien:

 string myString = "abc"; object myObj = myString; Type myObjType = myObj.GetDeclaredType(); string myNullString = null; object myNullObj = myNullString; Type myNullObjType = myNullObj.GetDeclaredType(); 

Tenga en cuenta que myObjType y myNullObjType se establecerán en System.Object, no System.String.

Si realmente desea el tipo de contenido del obj cuando no es nulo, cambie la línea de return a:

 return (obj != null) ? obj.GetType() : typeof( T ); 

Actualmente no tienes forma de saber qué pasa al método. Puede convertirlo en un método genérico. Me gusta esto:

public void GetParameterValue(out T destination) { ... }

El tipo de su variable de destino siempre es System.Object . Podrías simplemente regresar

 Convert.ChangeType(paramVal, System.Object). 

@ Rally25s:

 string val; GetParameterValue("parameterName", out val); 

No está claro a partir de su mensaje (en las respuestas) cuál fue el problema con ese. Si se declara como:

 void GetParameterValue(string parameterName, out T val) { } 

Que la llamada, como la escribió anteriormente, funcionará (no necesita especificar el tipo). Supongo que eso no funcionó para ti porque no puedes usar una propiedad como un parámetro de “salida”. La forma de evitarlo es usar ambos métodos:

 T GetParameterValue(string parameterName, T ununsed) { } 

Esto se llamaría así:

 MyObj.SomeProp = GetParameterValue("parameterName", MyObj.SomeProp); 

que es más bien tonto, pero no el peor método presentado.


Un método diferente, que he usado en C ++, pero aún no lo he intentado en C #, es tener GetParameterValue () algún objeto de tu propio diseño, y luego implementar una cantidad de operadores de conversión implícitos para él.

 class ParameterHelper { private object value; public ParameterHelper(object value) { this.value = value; } public static implicit operator int(ParameterHelper v) { return (int) v.value; } } ParameterHelper GetParameterValue( string parameterName); MyObj.SomeProp = GetParameterValue("parameterName"); 

No creo que sea posible obtener el tipo cuando el valor es nulo. Además, como llamas dentro de GetParameterValue, lo mejor que puedes hacer (cuando el valor es nulo) es obtener el tipo del parámetro “destino” que es “objeto”. Puede considerar pasar el Tipo como parámetro a GetParameterValue donde tiene más información, como por ejemplo:

 public void GetParameterValue(Type sourceType, out object destination) { //... } 

Si no hay instancia, no hay ningún tipo de instancia.

Lo mejor que puede hacer es usar el tipo de referencia, lo que significa que si tiene una referencia de objeto (como en el método en la pregunta), el tipo de referencia es el objeto.


Probablemente no deberías tratar de convertir una instancia nula de un tipo en una instancia nula de otro tipo …

En su ejemplo, sería nulo de tipo System.Object .

¿Tu ejemplo incluso comstack? Aparece el error “no se puede convertir de ‘cabo de cadena’ a ‘objeto de salida’.

En un nivel teórico, ¿no es un nulo realmente el mismo que un puntero de vacío en C, lo que quiere decir que tiene una dirección de memoria y eso es todo? Si es así, es similar al caso de una división por cero en Matemáticas donde el resultado no está definido.

Uno podría hacer lo siguiente para esta línea:

 string val = GetParameterValue("parameterName"); 

Solo elimina esa primera cadena y ahora no hay repetición:

 var val = GetParameterValue("parameterName"); 

No necesariamente lo que está buscando, aunque está la pregunta de ¿cómo interpreta uno nulo?

 //**The working answer** //**based on your discussion eheheheheeh** public void s(out T varName) { if (typeof (T) == typeof(HtmlTable)) { ////////// } } protected void Page_Load(object sender, EventArgs e) { HtmlTable obj=null ; s(out obj); } 

http://msdn.microsoft.com/en-us/library/58918ffs.aspx

o

 private Hashtable propertyTable = new Hashtable(); public void LoadPropertyTypes() { Type t = this.GetType(); System.Reflection.MemberInfo[] memberInfo = t.GetMembers(); foreach (System.Reflection.MemberInfo mInfo in memberInfo) { string[] prop = mInfo.ToString().Split(Convert.ToChar(" ")); propertyTable.Add(prop[1], prop[0]); } } public string GetMemberType(string propName) { if (propertyTable.ContainsKey(propName)) { return Convert.ToString(propertyTable[propName]); } else{ return "N/A"; } } 

de esa forma podemos usar el interruptor para administrar diferentes tipos de propiedades.