inizializzazione del campo con il costruttore di default
-
27-10-2019 - |
Domanda
public class Sample
{
static int count = 0;
public int abc;
public Sample()
{
abc = ++Sample.count;
}
}
Voglio creare un array di classe superiore, e desidera che ogni elemento della matrice da inizializzare invocando il costruttore di default, in modo che ogni elemento può avere diversi abc
.So ho fatto questo:
Sample[] samples = new Sample[100];
Ma questo non fa quello che penso che dovrebbe fare. Sembra che in questo modo il costruttore di default non è sempre chiamato. Come richiamare costruttore di default quando si crea un array?
Mi piacerebbe anche sapere che cosa fa la dichiarazione di cui sopra?
Soluzione
Non è possibile, in fondo. Quando si crea un array, è sempre inizialmente popolato con il valore di default per il tipo - che per una classe è sempre un riferimento null. Per int
è 0, per bool
è falso, ecc.
(Se si usa un inizializzatore matrice, che creerà il "vuoto" matrice e poi popolarlo con i valori che hai specificato, naturalmente.)
Ci sono vari modi di popolamento della matrice chiamando il costruttore - mi sarebbe probabilmente basta usare un ciclo foreach me stesso. Utilizzando LINQ con Enumerable.Range / Repeat sente un po 'forzata.
Naturalmente, si può sempre di scrittura il proprio metodo di popolazione, anche come un metodo di estensione:
public static T[] Populate<T>(this T[] array, Func<T> provider)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = provider();
}
return array;
}
Allora si potrebbe usare:
Sample[] samples = new Sample[100].Populate(() => new Sample());
Quello che mi piace di questa soluzione:
- E 'ancora una sola espressione, che può essere utile in diversi scenari
- Non ha introdurre concetti in realtà non desiderate (come la ripetizione di un singolo valore o la creazione di una serie)
Naturalmente si potrebbe aggiungere ulteriori opzioni:
- Un sovraccarico che prende un
Func<int, T>
invece di unFunc<T>
, passando l'indice al provider - Un metodo non estensione che crea l'array e popola
Altri suggerimenti
Il codice crea solo il array , ma nessuno dei suoi elementi. In sostanza, è necessario memorizzare istanze di Sample
in questo array.
Per dirla semplice, senza alcuna fantasia LINQ, ecc.
Sample[] samples = new Sample[100];
for (int i = 0; i < samples.Length; i++) samples[i] = new Sample();
Si prega di notare anche la soluzione è non thread-safe.
Non c'è modo per farlo automaticamente; inizializzazione array è essenzialmente "cancellare questo blocco di memoria 0s". Si dovrebbe fare qualcosa di simile:
var arr = new SomeType[size];
for(int i = 0 ; i < size ; i++) arr[i] = new SomeType();
A questo punto si dispone di una matrice vuota di dimensione 100, se si desidera riempire con oggetti, allora si dovrebbe fare qualcosa di simile:
for(int i=0; i<samples.Length; i++) {
samples[i] = new Sample();
}
Il problema è che, dichiarando tale matrice, non hai mai assegnato lo spazio per ogni oggetto. È semplicemente assegnato lo spazio per 100 oggetti di tipo Sample. Dovrete chiamare il costruttore su ogni te stesso.
Per approfondire:
Food[] foods = Food[100];
for (int k = 0; k < foods.length; k++) {
foods[k] = new Food();
}
Un lavoro interessante intorno potrebbe essere una funzione di fabbrica. Considerate questo allegando alla classe di esempio.
public static Sample[] getInstances(int aNumber) {
Sample[] sample = Sample[aNumber];
for (int k = 0; k < sample.length; k++) {
sample[k] = new Sample();
}
return sample;
}
Nasconde la macchia, un po '-. Fornisce questa è una funzione utile a voi
Ecco un altro uno-liner che non richiede alcun metodo di estensione:
Sample[] array = Enumerable.Range(0, 100).Select(i => new Sample()).ToArray();
Un'altra opzione interessante è il suggerimento di Scott per di Jon risposta :
public static T[] Populate<T>(this T[] array)
where T : new()
{
for (int i = 0; i < array.Length; i++)
array[i] = new T();
return array;
}
Così si può fare:
Sample[] array = new Sample[100].Populate();