2009-03-25 6 views
19

Sono ancora nuovo in C# e sono stato alle prese con vari problemi sugli array. Ho una serie di oggetti di metadati (coppie valore nomi) e vorrei sapere come creare solo il numero di oggetti "InputProperty" di cui ho veramente bisogno. In questo ciclo ho arbitrariamente impostato il numero di elementi su 20 e provo a eseguire il salvataggio quando la voce diventa nullo ma il servizio web sul lato ricevente di questo non gli piace alcun elemento nullo passato ad esso:Come impostare la lunghezza dell'array in C# dinamicamente

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; 
} 

In sintesi, dire che ho solo 3 coppie di punti di chiamata nell'array di input sopra riportato? Piuttosto che allocare 20 elementi per l'array chiamato ip, come è possibile codificarlo, così l'IP è tanto grande quanto deve essere. L'oggetto di aggiornamento viene passato attraverso un altro webservice, quindi la serializzazione è importante (ad esempio, non posso usare namevaluecollection, ecc.).

p.s. L'unico modo per dare seguito a una domanda postata tramite la funzione "aggiungi commenti"?

risposta

20

Se non si desidera utilizzare un List, ArrayList, o da un'altra raccolta in modo dinamico-size e poi convertire in un array (questo è il metodo che raccomando, tra l'altro), quindi dovrai allocare l'array alla sua dimensione massima possibile, tenere traccia di quanti elementi hai inserito e quindi creare un nuovo array con solo quegli articoli in esso:

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 metodo alternativo sarebbe quello di assegnare sempre update.Items = ip; e poi ridimensionare, se necessario:

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

E 'meno codice, ma è probabile che finisce per fare la stessa quantità di lavoro (vale a dire creazione di un nuovo array e copia dei vecchi elementi).

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

In alternativa, è possibile utilizzare un elenco in questo modo:

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

Un'altra cosa che vorrei sottolineare, in C# è possibile delcare l'utilizzo variabile int in un ciclo for proprio all'interno del ciclo:

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

E solo perché sono in vena, ecco un modo più pulito per fare questo metodo di 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

penso che ti manca il problema qui - l'array di input, nvPairs, contiene valori nulli dopo quelli utili. Usare semplicemente la sua lunghezza non risolverà nulla. – Whatsit

+0

L'OP non lo ha mai specificato. Ho appena pensato che il nulla fosse un semplice controllo di sanità mentale. Se quello che stai dicendo è in realtà il caso, allora hai ragione. La lista sarebbe sicuramente la strada da percorrere. – BFree

+0

Hmm non ho pensato che potesse essere un controllo di sanità mentale. Questo è certamente possibile. – Whatsit

5

È necessario essere un array? Se utilizzi un ArrayList o uno degli altri oggetti disponibili in C#, non avrai questa limitazione al contenuto. Hashtable, IDictionnary, IList, ecc. Consentono tutti un numero dinamico di elementi.

+0

Sono d'accordo.Se hai bisogno della funzionalità di un array e hai una lunghezza dinamica, un ArrayList è la risposta più semplice ed evidente – TheTXI

+0

ArrayList? Siamo allergici ai generici? –

+0

michl86 commenta che l'uso di List e .ToArray alla fine è troppo lento. Sembra che ArrayList possa essere convertito in array nello stesso modo. Per il mio risultato finale ho bisogno di un array non di ArrayList. Le prestazioni sono pessime con .ToArray() prima del ritorno? –

2

È possibile utilizzare Elenco all'interno del metodo e trasformarlo in un array alla fine. Ma penso che se parliamo di un valore massimo di 20, il tuo codice è più veloce.

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

Codice adattato sopra. Ottenere "Impossibile trovare il nome dello spazio dei nomi 'Elenco' (manca una direttiva using o un riferimento all'assembly?) Anche questo (che altro potrebbe volere): utilizzando System.Collections; using System .Collections.Generic; utilizzando System.Collections.Specialized; –

+0

Non importa ... capito ora. –

2

O in C# 3.0 utilizzando System.Linq è possibile saltare 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

ti dimentichi di controllare se nv è nullo –

0

In genere, gli array richiedono costanti per inizializzare la loro dimensione. Si può spazzare via una volta NvPairs per ottenere la lunghezza, quindi creare "dinamicamente" una matrice usando una variabile per una lunghezza come questa.

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

Non lo consiglierei comunque.Basta attaccare con il

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

soluzione. Non è molto meno performante e ha un aspetto migliore.

4

Utilizzare questa:

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

Usa Array.CreateInstance creare dinamicamente un array.

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

È possibile creare un array dinamico in questo modo:

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]; 

    }