dinamicos - objeto de objetos c#
¿Por qué está lanzando una dinámica de tipo objeto a objeto lanzando una excepción de referencia nula? (4)
Este es un comportamiento realmente extraño, y de hecho parece un error en la implementación de la dynamic
. Descubrí que esta variación no arroja una excepción y de hecho devuelve el objeto:
public static T TryGetArrayValue<T>(object[] array, int index) where T : class
{
dynamic boxed = array[index];
return boxed as T;
}
Tenga en cuenta que tuve que agregar una restricción genérica en la firma del método porque el operador as
solo funciona si T
es un tipo de referencia.
Si está buscando una solución, puede usar esto (y sé que es feo):
public static T TryGetArrayValue<T>(object[] array, int index)
{
dynamic boxed = array[index];
if (typeof(T) == typeof(object))
return (T)(boxed as object);
return (T)boxed;
}
Tengo la siguiente función:
public static T TryGetArrayValue<T>(object[] array_, int index_)
{
... //some checking goes up here not relevant to question
dynamic boxed = array_[index_];
return (T)boxed;
}
Cuando lo llamo de la siguiente manera,
object a = new object();
object v = TUtils.TryGetArrayValue<object>(new object[] { a }, 0);
(T)boxed
arroja una excepción de referencia nula.
Cualquier otro tipo que coloque allí aparte de "objeto", funciona perfectamente bien.
¿Alguna idea de qué es esto y por qué arroja la excepción?
Editar: La razón por la que uso dynamic es para evitar excepciones al convertir tipos, por ejemplo:
double a = 123;
int v = TUtils.TryGetArrayValue<int>(new object[] { a }, 0);
Este es un problema con el funcionamiento dinámico: el enlazador de tiempo de ejecución tiene un problema con las conversiones de System.Object
, pero en la práctica, realmente no es un problema.
Sospecho que esto es porque dynamic
, en tiempo de ejecución, es en sí mismo siempre System.Object
. La especificación de lenguaje C # en 4.7 establece: "La dinámica de tipo no se puede distinguir de un objeto en tiempo de ejecución". Como tal, cualquier objeto utilizado como dinámico simplemente se almacena como un objeto.
Cuando coloca una instancia real de System.Object
en una dinámica, ocurre algo dentro de la resolución de enlace de tiempo de ejecución que causa una excepción de referencia nula.
Sin embargo, cualquier otro tipo que no sea System.Object
funciona, incluso los tipos de referencia y similares, sin fallas. Como tal, esto debería proporcionarle el comportamiento adecuado, ya que realmente no hay motivos para crear una instancia de System.Object
sí que se transmita, siempre querría una subclase con otra información de tipo.
Tan pronto como utilice cualquier tipo "real", esto funciona bien. Por ejemplo, los siguientes trabajos, aunque se pasen y se traten como Object
:
public class Program
{
public static T TryGetArrayValue<T>(object[] array_, int index_)
{
dynamic boxed = array_[index_];
return (T)boxed;
}
private static void Main()
{
int p = 3;
object a = p;
var objects = new[] { a, 4.5 };
// This works now, since the object is pointing to a class instance
object v = TryGetArrayValue<object>(objects, 0);
Console.WriteLine(v);
// These both also work fine...
double d = TryGetArrayValue<double>(objects, 1);
Console.WriteLine(d);
// Even the "automatic" int conversion works now
int i = TryGetArrayValue<int>(objects, 1);
Console.WriteLine(i);
Console.ReadKey();
}
}
Estoy de acuerdo con los otros que dicen que esto parece un error. Específicamente, parece ser un error en la capa de enlace de tiempo de ejecución C #, aunque no lo he investigado a fondo.
Me disculpo por el error. Lo informaré al equipo de pruebas C # 5 y veremos si ya se informó y se corrigió en C # 5. (Se reproduce en la versión beta reciente, por lo que es poco probable que ya se haya informado y solucionado). ) De lo contrario, es poco probable que una solución llegue a la versión final. En ese caso, lo consideraremos para una posible publicación de servicio.
Gracias por traer esto a nuestra atención. Si le apetece ingresar un problema de Connect para seguirlo, siéntase libre de hacerlo e incluya un enlace a esta pregunta de . Si no lo haces, no hay problema; el equipo de prueba lo sabrá de cualquier manera.
Tiene algo que ver con la palabra clave dinámica. Si cambio el tipo a T para en caja, funciona.
static void Main(string[] args)
{
object a = new object();
object v = TryGetArrayValue<object>(new object[] { a }, 0);
Console.ReadLine();
}
public static T TryGetArrayValue<T>(object[] array_, int index_)
{
T boxed = (T)array_[index_];
return boxed;
}
¿Hay alguna razón particular por la que está usando dinámica? Realmente no lo necesita en este caso, ya que sabe de antemano cuál es el tipo. Si mira, en su versión, el tipo de recuadro no es objeto, pero es {objeto} dinámico, que podría ser el problema cuando intente lanzar al objeto. Si miras esta versión que publiqué, obtienes un tipo de objeto y ningún error.