2008-10-31 27 views
26

Tengo un método con un parámetro out que intenta hacer una conversión de tipo. Básicamente:.NET: ¿Cómo se obtiene el tipo de objeto nulo?

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 por lo general alguien llamaría a esto como:

string output; 
GetParameterValue(output); 

Esto va a fracasar por:

destination.GetType() 

destino es nula, por lo que no se puede llamar .GetType() en él. Tampoco podemos llamar:

typeof(destination) 

porque el destino no es un nombre de variable de 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.


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

Qué sería lo ideal sería que los desarrolladores a hacer algo como:

string val = GetParameterValue("parameterName"); 

Lo notable es que no hay una fundición de tipos. En la práctica, no se sabe la lparam de la "iguales", así que fui con:

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

y pensamos que dentro del método, me gustaría saber 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<T>(string paramName) 

Así que los desarrolladores pueden hacer:

string val = GetParameterValue<string>("parameterName"); 

puedo encontrar la declaración explícita "cadena" de ser repetitivo, sobre todo porque en la práctica, el destino si probablemente una propiedad de objeto y el tipo de datos de Oracle podrían cambiar (piensa ORM):

MyObj.SomeProp = GetParameterValue<MyObj.SomeProp.GetType()>("parameterName"); 

Pero de nuevo, si MyObj.SomeProp es nulo, que .GetType() llamada 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, que puedo hacer:

MyObj.SomeProp = GetParameterValue<typeof(MyObj).GetField("SomeProp").GetType()>("parameterName"); 

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

Respuesta

29

Entonces, ¿hay alguna manera de obtener el tipo de un objeto que se establece en null? 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 object. Una referencia null no apunta a ninguna ubicación de almacenamiento, por lo que no hay metadatos que puedan hacer esa determinación.

Lo mejor que se puede hacer es cambiar que sea más genérico, como en:

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

El tipo de T se puede inferir, por lo que no es necesario dar un parámetro de tipo con el método explícitamente.

+0

¡Buena sugerencia! El segundo argumento debe ser typeof (T) y no typeof (T) .GetType(). – Hallgrim

+0

desafortunadamente ese código "out T dest" no se compila porque no puede encontrar el tipo "T". Investigaré esta opción un poco más ... – CodingWithSpike

+0

@ rally25rs: la T es un tipo genérico, en este caso lo que se sugiere es que use genéricos para determinar el tipo de método. –

0

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

¿Su ejemplo incluso compila? Aparece el error "no se puede convertir de 'cabo de cadena' a 'objeto de salida'.

+0

mis pruebas unitarias para que se compile, pero que tenía el actual cabo conjunto de variables a un objeto no es una cadena. – CodingWithSpike

2

El tipo de la variable de destino siempre es System.Object. Simplemente puede devolver

Convert.ChangeType(paramVal, System.Object). 
3

Actualmente no tiene forma de saber qué se pasa al método. Puede convertirlo en un método genérico. De esta manera:

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

+0

De hecho, hice este mismo método como una segunda forma de obtener los mismos datos. Estaba funcionando, así que no lo incluí en mi publicación :) – CodingWithSpike

0

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". Usted puede ser que considerar la aprobación del tipo como un parámetro para getParameterValue donde se tiene más información, tales como:

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

Es posible, si no le importa declarar su método como un genérico. Prueba esto.

class Program 
{ 
    public static void GetParameterValue<T>(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); 
    } 
} 
0

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

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


Es probable que no debe estar tratando de convertir una instancia de un tipo nulo en una instancia nula de otro tipo ...

1

@ Rally25s:

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

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

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

Que la llamada, como lo ha escrito más arriba, va a trabajar (que no es necesario 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 evitar esto es utilizar ambos métodos:

T GetParameterValue<T>(string parameterName, T ununsed) { } 

esto se llamaría así:

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

que es bastante kludgey, pero no el método presentado peor.


Un método diferente, que he utilizado en C++, pero no he probado todavía en C#, es tener getParameterValue() algún objeto de que el propietario del diseño, y luego poner en práctica una serie de operadores de conversión implícitas para ello.

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"); 
+0

Marcus editó su respuesta después de que la leí. Originalmente tenía "GetParameterValue (out T dest)", en lugar de "GetParameterValue (...)". Su respuesta editada es correcta. – CodingWithSpike

0

A nivel teórico no es un nulo realmente lo mismo que un puntero nulo en C, es decir, que posee 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.

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

string val = GetParameterValue<string>("parameterName"); 

Basta con retirar la primera cuerda y ahora no es la repetición:

var val = GetParameterValue<string>("parameterName"); 

no necesariamente lo que está buscando, aunque está la cuestión de cómo se interpreta uno nulo?

+0

El problema no era "qué tipo de nulo son", era "cuál es el tipo de ubicación de almacenamiento que actualmente se establece en nulo" Entonces "DataTable dt = null", la VM todavía sabe que dt es de tipo DataTable . – CodingWithSpike

+0

Al establecer una variable como nula, no apunta a nada, es mi punto. Si tiene 3 clases donde cada una deriva de otra, p. A se deriva de B y B se deriva de C, y usted tenía una variable de tipo B que tiene asignado nulo, ¿no podría asignarle una variable de tipo A o no? –

0
//**The working answer** 

//**based on your discussion eheheheheeh** 

public void s<T>(out T varName) 
{ 
    if (typeof (T) == typeof(HtmlTable)) 
    { 
     //////////  
    } 

} 

protected void Page_Load(object sender, EventArgs e) 
{ 
    HtmlTable obj=null ; 
    s(out obj);  
} 
-1

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 manera podemos usar el interruptor para manejar diferentes tipos de propiedad.

7

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

using System; 

namespace MyNamespace 
{ 
    public static class Extensions 
    { 
     /// <summary> 
     /// Gets the declared type of the specified object. 
     /// </summary> 
     /// <typeparam name="T">The type of the object.</typeparam> 
     /// <param name="obj">The object.</param> 
     /// <returns> 
     /// A <see cref="Type"/> object representing type 
     /// <typeparamref name="T"/>; i.e., the type of <paramref name="obj"/> 
     /// as it was declared. Note that the contents of 
     /// <paramref name="obj"/> are irrelevant; if <paramref name="obj"/> 
     /// contains an object whose class is derived from 
     /// <typeparamref name="T"/>, then <typeparamref name="T"/> is 
     /// returned, not the derived type. 
     /// </returns> 
     public static Type GetDeclaredType<T>(
      this T obj) 
     { 
      return typeof(T); 
     } 
    } 
} 

Dado que este es un método de extensión, su argumento puede ser una referencia nula, y todo de las siguientes obras: OK

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 ambas funciones fijas a System.Object, no System.String.

Si realmente se desea que el tipo de contenido del obj cuando no nula, a continuación, cambiar la línea return a:

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

Obtendrá RuntimeBinderException si obj se declara como dinámico. –

Cuestiones relacionadas