2012-02-08 9 views
8

Ho una lista statica di grandi dimensioni che è fondamentalmente una tabella di ricerca, quindi inizializzo la tabella in codice.Utilizzo della sintassi di inizializzatore della raccolta su tipi personalizzati?

private class MyClass 
{ 
    private class LookupItem 
    { 
     public int Param1 { get; set; } 
     public int Param2 { get; set; } 
     public float Param2 { get; set; } 
     public float Param4 { get; set; } 
    } 

    private static List<LookupItem> _lookupTable = new List<LookupItem>() 
    { 
     new LookupItem() { Param1 = 1, Param2 = 2, Param3 = 3 Param4 = 4 }, 
     new LookupItem() { Param1 = 5, Param2 = 6, Param3 = 7 Param4 = 8 }, 
     //etc 
    } 
} 

Il vero LookupItem ha molte più proprietà, così ho aggiunto un costruttore per consentire un formato di inizializzazione più compatto:

private class MyClass 
{ 
    private class LookupItem 
    { 
     public int Param1 { get; set; } 
     public int Param2 { get; set; } 
     public float Param2 { get; set; } 
     public float Param4 { get; set; } 

     public LookupItem(int param1, int param2, float param3, float param4) 
     { 
      Param1 = param1; 
      Param2 = param2; 
      Param3 = param3; 
      Param4 = param4;  
     } 
    } 

    private static List<LookupItem> _lookupTable = new List<LookupItem>() 
    { 
     new LookupItem(1, 2, 3, 4), 
     new LookupItem(5, 6, 7, 8), 
     //etc 
    } 
} 

Quello che mi piacerebbe davvero fare è utilizzare la collezione initialiser formato per l'oggetto stesso così posso liberarmi di new LookupItem() su ogni linea. es .:

private static List<LookupItem> _lookupTable = new List<LookupItem>() 
{ 
    { 1, 2, 3, 4 }, 
    { 5, 6, 7, 8 }, 
    //etc 
} 

È possibile? Mi piace pensare che sia perché lo KeyValuePair di un Dictionary<> può essere inizializzato in questo modo.

MSDN Uniti:

initializers Collection consentono di specificare uno o più elementi intializers quando si inizializza una classe collezione che implementa IEnumerable . Gli inizializzatori dell'elemento possono essere un valore semplice, un'espressione o un inizializzatore di oggetto. Utilizzando un inizializzatore di raccolta non è necessario specificare più chiamate al metodo Aggiungi della classe nel codice sorgente; il compilatore aggiunge le chiamate.

Ciò significa che è necessario implementare IEnumerable nella mia classe LookupItem e restituire ciascun parametro? La mia classe non è però una classe di raccolta.

risposta

11

Penso che sia necessario creare una raccolta personalizzata anziché Elenco. Chiamalo LookupItemTable, ad esempio. Dare a quella raccolta un metodo Add (int, int, float, float) e farlo implementare IEnumerable. Ad esempio:

class LookupItem 
{ 
    public int a; 
    public int b; 
    public float c; 
    public float d; 
} 

class LookupItemTable : List<LookupItem> 
{ 
    public void Add(int a, int b, float c, float d) 
    { 
     LookupItem item = new LookupItem(); 
     item.a = a; 
     item.b = b; 
     item.c = c; 
     item.d = d; 
     Add(item); 
    } 
} 

private static LookupItemTable _lookupTable = new LookupItemTable { 
    { 1, 2, 3, 4 }, 
    { 5, 6, 7, 8 } 
}; 

Ora ho provato il codice sopra e sembra funzionare per me.

+0

Fantastico. Grazie mille. – GazTheDestroyer

4

si sta cercando di utilizzare un inizializzatore raccolta nella lista stessa, non sul tipo:

// Note the "new List<...>" part - that specifies what type the collection 
// initializer looks at... 
private static List<LookupItem> _lookupTable = new List<LookupItem>() 
{ 
    { 1, 2, 3, 4 }, 
    { 5, 6, 7, 8 }, 
} 

quindi è alla ricerca di un metodo Add con quattro parametri su List<T>, e che non esiste.

Per utilizzare un inizializzatore di raccolta personalizzato, è necessario implementare la propria classe per la raccolta . Mentre stai usando List<T>, sei bloccato con le chiamate del costruttore che hai.

0

Ciò significa che è necessario implementare IEnumerable sulla classe LookupItem e restituire ciascun parametro? La mia classe non è però una classe di raccolta.

No, significa che List<LookupItem> implementa IEnumerable, che è il motivo per cui è possibile scrivere

private static List<LookupItem> _lookupTable = new List<LookupItem>() 
{ 
    new LookupItem(1, 2, 3, 4), 
    new LookupItem(5, 6, 7, 8), 
    //etc 
} 

Ciò significa anche che se il vostro LookupItem era una collezione che ha implementato IEnumerable, si potrebbe scrivere:

private static List<LookupItem> _lookupTable = new List<LookupItem>() 
{ 
    new LookupItem { new Item(), new Item() }, 
    new LookupItem { new Item(), new Item() } 
} 
5

Correzione rapida: Crea il tuo tipo con un Add overload che accetta più argomenti:

class LookupList : List<LookupItem> { 
    public void Add(int Param1, int Param2, ... sometype ParamX) { 
     this.Add(new LookupItem() { Param1 = Param1, Param2 = Param2, ... ParamX = ParamX }); 
    } 
} 

ora funziona esattamente come si desidera:

private static LookupList _lookupTable = new LookupList() {     
     {1,2,3,4},     
     {2,7,6,3}     
    }; 

risposta più fondamentale:

Stai mescolando object initializers e collection initializers. In parole semplici:

Gli inizializzatori di oggetti sono un trucco sintattico che, in background, chiama i metodi dell'insieme di proprietà per ciascuna proprietà denominata con il valore specificato.

Collection initializers sono un trucco sintattica che, sullo sfondo:

  • Per un tipo di Array: riempire l'array con gli articoli
  • Per qualsiasi altro tipo, che devono implementare IEnumerable: Chiamare il Add metodo per ogni sottogruppo impostato.

Questo è all c'è. Si consideri ad esempio il seguente trucco:

public class Hack : IEnumerable { 
    public int LuckyNumber { get; set; } 
    public double Total { get; private set; } 
    public void Add(string message, int operand1, double operand2, double operand3) { 
     Console.WriteLine(message); 
     this.Total += operand1 * operand2 - operand3; 
    } 
    public IEnumerator GetEnumerator() { throw new NotImplementedException(); } 
} 

class Program { 
    static void Main(string[] args) { 
     Hack h1 = new Hack() { 
      { "Hello", 1, 3, 2}, 
      { "World", 2, 7, 2.9} 
     }; 
     Console.WriteLine(h1.Total); 
     Hack h2 = new Hack() { LuckyNumber = 42 }; 
     Console.WriteLine(h2.LuckyNumber); 
    } 
} 

non si dovrebbe mai fare questo in un programma vero e proprio, ma spero di esaminare questo esempio ei risultati, soprattutto se si esegue il debug passo attraverso di essa, vi aiuterà a capire le inizializzatori in modo chiaro e scegli una buona soluzione per il tuo scenario attuale.

+0

'Non dovresti mai farlo in un programma reale' - ok. Cosa dovresti fare in un vero programma? Scenario: porting da Java, e avere una classe con 3 'Add()' overload e implementa 'IEnumerable '. Se implemento 'ICollection ' avrò un po 'di metodi 'Remove()', 'Clear()' che non desidero o di cui ho bisogno. Esiste un'altra soluzione per rendere più chiaro come utilizzare gli inizializzatori di raccolta usando Intellisense, o la documentazione è la mia unica opzione? – NightOwl888

Problemi correlati