2009-03-25 8 views
19

Todavía soy nuevo en C# y he estado luchando con varios problemas en las matrices. Tengo una serie de objetos de metadatos (pares de nombre y valor) y me gustaría saber cómo crear solo el número de objetos "InputProperty" que realmente necesito. En este bucle, he establecido arbitrariamente el número de elementos en 20 e intento rescatar cuando la entrada se vuelve nula, pero el servicio web en el extremo receptor no tiene ningún elemento nulo:Cómo configurar la longitud de la matriz en C# dinámicamente

private Update BuildMetaData(MetaData[] nvPairs) 
{ 
    Update update = new Update(); 
    InputProperty[] ip = new InputProperty[20]; // how to make this "dynamic" 
    int i; 
    for (i = 0; i < nvPairs.Length; i++) 
    { 
     if (nvPairs[i] == null) break; 
     ip[i] = new InputProperty(); 
     ip[i].Name = "udf:" + nvPairs[i].Name; 
     ip[i].Val = nvPairs[i].Value; 
    } 
    update.Items = ip; 
    return update; 
} 

En resumen, supongamos que solo tengo 3 pares de valores de nombre en la matriz de entrada anterior. En lugar de asignar 20 elementos para la matriz denominada ip, ¿cómo se puede codificar esto para que la ip sea tan grande como debe ser? El objeto de actualización se pasa a través de otro servicio web, por lo que la serialización es importante (es decir, no puedo usar namevaluecollection, etc.).

p.s. ¿Es la única forma de seguimiento de una pregunta publicada a través de la función "agregar comentarios"?

Respuesta

20

Si no desea utilizar un List, ArrayList, u otra colección dinámica de tamaño y luego convertir a una matriz (ese es el método que yo recomendaría, por cierto), entonces tendrá que asignar la matriz a su tamaño máximo posible, realizar un seguimiento de la cantidad de elementos que pone en ella, y luego crear una nueva matriz con solo esos artículos en él:

private Update BuildMetaData(MetaData[] nvPairs) 
{ 
    Update update = new Update(); 
    InputProperty[] ip = new InputProperty[20]; // how to make this "dynamic" 
    int i; 
    for (i = 0; i < nvPairs.Length; i++) 
    { 
     if (nvPairs[i] == null) break; 
     ip[i] = new InputProperty(); 
     ip[i].Name = "udf:" + nvPairs[i].Name; 
     ip[i].Val = nvPairs[i].Value; 
    } 
    if (i < nvPairs.Length) 
    { 
     // Create new, smaller, array to hold the items we processed. 
     update.Items = new InputProperty[i]; 
     Array.Copy(ip, update.Items, i); 
    } 
    else 
    { 
     update.Items = ip; 
    } 
    return update; 
} 

Un método alternativo sería asignar siempre update.Items = ip; y luego cambiar el tamaño si es necesario:

update.Items = ip; 
if (i < nvPairs.Length) 
{ 
    Array.Resize(update.Items, i); 
} 

Es menos código, pero probablemente va a terminar haciendo la misma cantidad de trabajo (es decir, creando una nueva matriz y copiando los elementos antiguos).

27
InputProperty[] ip = new InputProperty[nvPairs.Length]; 

O bien, puede utilizar una lista de este modo:

List<InputProperty> list = new List<InputProperty>(); 
InputProperty ip = new (..); 
list.Add(ip); 
update.items = list.ToArray(); 

Otra cosa que me gustaría señalar, en C# se puede delcare su uso variable entero en un bucle justo dentro de la loop:

for(int i = 0; i<nvPairs.Length;i++ 
{ 
. 
. 
} 

Y sólo porque estoy en el estado de ánimo, he aquí una forma más limpia de hacer este método IMO:

private Update BuildMetaData(MetaData[] nvPairs) 
{ 
     Update update = new Update(); 
     var ip = new List<InputProperty>(); 

     foreach(var nvPair in nvPairs) 
     { 
      if (nvPair == null) break; 
      var inputProp = new InputProperty 
      { 
       Name = "udf:" + nvPair.Name, 
       Val = nvPair.Value 
      }; 
      ip.Add(inputProp); 
     } 
     update.Items = ip.ToArray(); 
     return update; 
} 
+0

creo que se está perdiendo el problema aquí - la matriz de entrada, nvPairs, contiene valores nulos después de los útiles. Simplemente usar su longitud no resolverá nada. – Whatsit

+0

El OP nunca especificó eso. Solo asumí que si null era un simple control de cordura. Si lo que dices es, de hecho, el caso, entonces tienes razón. La lista definitivamente sería el camino a seguir. – BFree

+0

Hmm No pensé que podría ser un control de cordura. Eso es ciertamente posible. – Whatsit

5

¿Es necesario que sea una matriz? Si usa una ArrayList u otro de los objetos disponibles en C#, no tendrá esta limitación para el contenido. Hashtable, IDictionnary, IList, etc. permiten un número dinámico de elementos.

+0

Estoy de acuerdo. Si necesita la funcionalidad de una matriz y tiene una longitud dinámica, una ArrayList es la respuesta más simple y obvia. – TheTXI

+0

ArrayList? Somos alérgicos a los genéricos? –

+0

michl86 comenta que el uso de List y .ToArray al final es demasiado lento. Parece que ArrayList se puede convertir a una matriz de la misma manera. Para mi resultado final, necesito una matriz, no ArrayList. ¿El rendimiento es malo con .ToArray() justo antes de regresar? –

2

Puede usar List dentro del método y transformarlo en una matriz al final. Pero creo que si hablamos de un valor máximo de 20, su código es más rápido.

private Update BuildMetaData(MetaData[] nvPairs) 
    { 
     Update update = new Update(); 
     List<InputProperty> ip = new List<InputProperty>(); 
     for (int i = 0; i < nvPairs.Length; i++) 
     { 
      if (nvPairs[i] == null) break; 
      ip[i] = new InputProperty(); 
      ip[i].Name = "udf:" + nvPairs[i].Name; 
      ip[i].Val = nvPairs[i].Value; 
     } 
     update.Items = ip.ToArray(); 
     return update; 
    } 
+0

Código adaptado anterior. Obteniendo "No se encontró el tipo o el nombre del espacio de nombres 'Lista' (¿falta una directiva using o una referencia de ensamblado?) Tengo esto también (qué más podría querer): usando System.Collections; using System .Collections.Generic; using System.Collections.Specialized; –

+0

No importa ... ahora lo tengo. –

2

O en C# 3.0 utilizando System.Linq puede saltarse la lista intermedia:

private Update BuildMetaData(MetaData[] nvPairs) 
{ 
     Update update = new Update(); 
     var ip = from nv in nvPairs 
       select new InputProperty() 
       { 
        Name = "udf:" + nv.Name, 
        Val = nv.Value 
       }; 
     update.Items = ip.ToArray(); 
     return update; 
} 
+0

se olvida comprobar si nv es nulo –

0

Normalmente, las matrices requieren constantes para inicializar su tamaño. Podrías barrer nvPairs una vez para obtener la longitud, luego "dinámicamente" crear una matriz usando una variable de una longitud como esta.

InputProperty[] ip = (InputProperty[])Array.CreateInstance(typeof(InputProperty), length); 

No lo recomendaría, sin embargo.Simplemente quédate con el

List<InputProperty> ip = ... 
... 
update.Items = ip.ToArray(); 

solución. No es mucho menos eficiente y mucho más atractivo.

4

Utilice esta:

Array.Resize(ref myArr, myArr.Length + 5); 
1

Uso Array.CreateInstance para crear una matriz dinámica.

private Update BuildMetaData(MetaData[] nvPairs) 
    { 
     Update update = new Update(); 
     InputProperty[] ip = Array.CreateInstance(typeof(InputProperty), nvPairs.Count()) as InputProperty[]; 
     int i; 
     for (i = 0; i < nvPairs.Length; i++) 
     { 
      if (nvPairs[i] == null) break; 
      ip[i] = new InputProperty(); 
      ip[i].Name = "udf:" + nvPairs[i].Name; 
      ip[i].Val = nvPairs[i].Value; 
     } 
     update.Items = ip; 
     return update; 
    } 
0

Puede crear una matriz dinámica de esta manera:

static void Main() 
    { 
     // Create a string array 2 elements in length: 
     int arrayLength = 2; 
     Array dynamicArray = Array.CreateInstance(typeof(int), arrayLength); 
     dynamicArray.SetValue(234, 0);        // → a[0] = 234; 
     dynamicArray.SetValue(444, 1);        // → a[1] = 444; 
     int number = (int)dynamicArray.GetValue(0);      // → number = a[0]; 


     int[] cSharpArray = (int[])dynamicArray; 
     int s2 = cSharpArray[0]; 

    } 
Cuestiones relacionadas