c# - vacio - .NET: ¿Cómo se obtiene el tipo de objeto nulo?
tag c# (12)
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<T>(string paramName)
Entonces los desarrolladores pueden hacer:
string val = GetParameterValue<string>("parameterName");
Encuentro que la declaración explícita de "cadena" es repetitiva, especialmente porque, en la práctica, el destino probablemente sea una propiedad del objeto y el tipo de datos del oráculo podría cambiar (piense en ORM):
MyObj.SomeProp = GetParameterValue<MyObj.SomeProp.GetType()>("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<typeof(MyObj).GetField("SomeProp").GetType()>("parameterName");
La idea era no tener que usar 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<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 debería necesitar dar un parámetro de tipo al método explícitamente.
@ Rally25s:
string val;
GetParameterValue("parameterName", out val);
No está claro a partir de su mensaje (en las respuestas) cuál fue el problema con eso. Si se declara como:
void GetParameterValue<T>(string parameterName, out T val) { }
Que la llamada, como la escribió anteriormente, funcionará (no es necesario que especifique 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<T>(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 que aún no he probado 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");
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<T>(out T destination) { ... }
En su ejemplo, sería nulo de tipo System.Object
.
¿Tu ejemplo incluso compila? 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<string>("parameterName");
Solo elimina esa primera cadena y ahora no hay repetición:
var val = GetParameterValue<string>("parameterName");
No necesariamente lo que está buscando, aunque está la pregunta de ¿cómo interpreta uno nulo?
Es posible si no te importa declarar tu método como 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);
}
}
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 ...
El tipo de su variable de destino siempre es System.Object
. Podrías simplemente regresar
Convert.ChangeType(paramVal, System.Object).
//**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);
}
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
{
/// <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 );
}
}
}
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 );
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.