2011-09-04 10 views
7
namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      object[] obj = new object[3]; 
      obj[0] = new object(); 
      obj[1] = "some string"; 
      obj[2] = 10; 

      string[] strings = new string[] { "one", "two", "three" }; 
      obj = strings; //---> No Error here, Why ? 

      int[] ints = new int[] { 1, 2, 3 }; 
      obj = ints; /*-> Compiler error - Cannot implicitly convert type 'int[]' to 'object[]', Why ?*/ 
     } 
    } 
} 

Recibo un error de compilación mientras hago el paso como se muestra arriba. Pero, en el paso anterior, no hay error. ¿Alguien puede explicarme este comportamiento? Estoy usando VS 2010.C# - Error del compilador - al asignar int [] al objeto []

EDITAR - Para completar, una vez más, esto no se compilará - El soporte de varianza en .NET 4.0 se ha limpiado ahora. Se pueden usar palabras clave nuevas en y en con parámetros de tipo genérico.

List<object> objectList = new List<object>(); 
    List<string> stringList = new List<string>(); 
    objectList = stringList; 
+2

¿Usted entiende las diferencias entre tipo de valor y tipos de referencia? – Oded

Respuesta

6

Sólo matrices de tipos de referencia (como String) pueden ser asignables a arrays de otros tipos de referencia (como Object). Como int es un tipo de valor, sus matrices no pueden asignarse a matrices de otros tipos.

Para ser más específicos, esto se llama array covariance. Solo funciona cuando los patrones de bits almacenados en la matriz son compatibles con el tipo de destino. Por ejemplo, los bits en un String[] son todas referencias a cadenas y se pueden copiar de forma segura en ubicaciones de memoria que almacenan referencias a objetos. Sin embargo, una variedad de tipos de valores almacena los datos reales de los elementos (en lugar de las referencias a ellos). Esto significa que un int[] almacena los enteros reales de 32 bits en los elementos de la matriz. Dado que un entero de 32 bits no se puede copiar de forma segura en una ubicación de memoria que almacena una referencia a un objeto o cualquier otro tipo, no se puede asignar una matriz de ellos a una matriz de ningún otro tipo.

Tenga en cuenta que técnicamente los bits de int se pueden copiar de forma segura en una ubicación de memoria que almacena un uint (y viceversa). Esto significa que debe poder hacer algo como int[] x = new uint[10]. Esto no es realmente covarianza y C# no lo permite. Sin embargo, es legal en el CLR y puede convencer a C# para que lo haga si así lo desea.

+0

Pero todo es finalmente system.object –

+0

Gracias Gabe. ¡La covarianza de matriz es la clave! –

1

lo que veo es que se puede asignar una matriz de tipos de referencia de otra matriz de tipos de referencia, mientras que una matriz de tipos de valores no. Tiene sentido para mí

2

string y object son ambos tipos de referencia. Es decir, una variable de esos tipos realmente almacena un puntero a otro lugar en la memoria. int es un tipo de valor. Es decir, los datos se almacenan directamente donde se declara la variable.

Esto significa que una matriz de tipos de referencia es fundamentalmente diferente a una matriz de tipos de valores. Una matriz de tipos de referencia se almacena como una matriz de punteros. Como los punteros son todos del mismo tamaño, esto significa que para volver a interpretar un string[] como object[] simpy, significa ajustar la comprobación de tipo realizada al acceder a los elementos del conjunto (en términos generales).

Sin embargo, en un int[], los valores se almacenan en la matriz directamente; los valores int se concatenan juntos. No hay indicadores involucrados. Esto significa que para volver a interpretar un int[] como object[] se requiere encajonar cada valor almacenado en el conjunto en un objeto. De ahí que no pueda hacerlo utilizando un simple molde o asignación: es una operación O (n) que crea una nueva matriz. En su lugar, puede usar Array.Copy que trata con todo el boxeo para usted.

0

Si tiene una instalación de Visual Studio, encontrará la especificación de idioma C# como archivo de documentación en algún lugar en VC#. Capítulo 12.5 trata de covarianza y allí se dice

Para cualquiera de los dos tipos de referencia A y B, si (§6.1.6) o la conversión referencia explícita (§6.2.4) existe una implícita referencia de la conversión de la A a B, también existe la misma conversión de referencia del matriz tipo A [R] a la matriz tipo B [R], donde R es cualquier especificador de rango (pero el mismo para ambos tipos de matriz). Esta relación se conoce como covarianza de matriz.

Esto puede no responder a su pregunta, pero fue una decisión deliberada en la especificación para hacerlo de esa manera.

1

Por qué eso no funciona está indicado en muchas respuestas aquí, así que no intentaré copiar y pegar lo que dijeron.

Si usted, o alguien realmente quiere hacer eso (convertir int[] a object[]) por alguna razón, puede utilizar LINQ, así:

int[] ints = new int[] { 1, 2, 3 }; 
object[] obj_ints = (from i in ints select i).Cast<object>().ToArray(); 

;)

+0

Puede haber muchas soluciones. Por favor, vea la respuesta de 'Gabe' debajo de –

+1

¿Por qué no simplemente usa 'Array.Copy'? http://msdn.microsoft.com/en-us/library/system.array.copy.aspx – Gabe

Cuestiones relacionadas