Diciamo che ho una classe come questa:Elegante l'inizializzazione di un array di istanze di classi in C#
public class Fraction
{
int numerator;
int denominator;
public Fraction(int n, int d)
{
// set the member variables
}
// And then a bunch of other methods
}
voglio inizializzare un array di loro in modo piacevole, e questo post è una grande lista di approcci che sono inclini all'errore o sintatticamente ingombranti.
Naturalmente un costruttore di array sarebbe bello, ma non c'è nulla di simile:
public Fraction[](params int[] numbers)
Quindi sono costretto a utilizzare un metodo come
public static Fraction[] CreateArray(params int[] numbers)
{
// Make an array and pull pairs of numbers for constructor calls
}
che è relativamente goffo, ma io non vedere un modo per aggirarlo.
Entrambe le forme sono soggette a errori perché un utente potrebbe erroneamente passare un numero dispari di parametri, forse perché ha saltato un valore, che lascerebbe la funzione grattarsi la testa chiedendosi cosa volesse effettivamente l'utente. Potrebbe generare un'eccezione, ma l'utente dovrebbe provare/catturare. Preferirei non imporlo all'utente, se possibile. Quindi applichiamo le coppie.
public static Fraction[] CreateArray(params int[2][] pairs)
Ma non si può chiamare questo CreateArray in un modo bello, come
Fraction.CreateArray({0,1}, {1,2}, {1,3}, {1,7}, {1,42});
Non si può nemmeno fare
public static Fraction[] CreateArray(int[2][] pairs)
// Then later...
int[2][] = {{0,1}, {1,2}, {1,3}, {1,7}, {1,42}};
Fraction.CreateArray(numDenArray);
Si noti che questo avrebbe funzionato bene in C++ (Sono abbastanza sicuro).
Sei costretto a fare uno dei seguenti invece, il che è aberrante. La sintassi è terribile e sembra davvero imbarazzante usare un array frastagliato quando tutti gli elementi hanno la stessa lunghezza.
int[2][] fracArray = {new int[2]{0,1}, /*etc*/);
Fraction.CreateArray(fracArray);
// OR
Fraction.CreateArray(new int[2]{0,1}, /*etc*/);
Allo stesso modo, le tuple in stile Python sono illegali e la versione C# è icky:
Fraction.CreateArray(new Tuple<int,int>(0,1), /*etc*/);
L'uso di una matrice 2D puro potrebbe assumere il seguente modulo, ma è illegale, e sono che non ci sia modo legale per esprimerlo:
public static Fraction[] CreateArray(int[2,] twoByXArray)
// Then later...
Fraction[] fracArray =
Fraction.CreateArray(new int[2,4]{{0,1}, {1,2}, {1,3}, {1,6}});
Ciò non far rispettare le coppie:
public static Fraction[] CreateArray(int[,] twoByXArray)
OK, come su
public static Fraction[] CreateArray(int[] numerators, int[] denominators)
Ma poi i due array possono avere diverse lunghezze. C++ consente
public static Fraction[] CreateArray<int N>(int[N] numerators, int[N] denominators)
ma, beh, questo non è C++, vero?
Questo genere di cose è illegale:
public static implicit operator Fraction[](params int[2][] pairs)
e impraticabile in ogni caso, sempre a causa della sintassi aberrante:
Fraction[] fracArray = new Fraction[](new int[2]{0,1}, /*etc*/);
Questo potrebbe essere bello:
public static implicit operator Fraction(string s)
{
// Parse the string into numerator and denominator with
// delimiter '/'
}
Poi si può fare
string[] fracStrings = new string[] {"0/1", /*etc*/};
Fraction[] fracArray = new Fraction[fracStrings.Length];
int index = 0;
foreach (string fracString in fracStrings) {
fracArray[index] = fracStrings[index];
}
Non mi piace questo approccio per cinque motivi. Uno, il cast implicito crea inevitabilmente un nuovo oggetto, ma ne abbiamo già uno perfetto, quello che stiamo cercando di inizializzare. Due, può essere fonte di confusione da leggere. Tre, ti costringe a fare esplicitamente ciò che volevo incapsulare in primo luogo. Quattro, lascia spazio alla cattiva formattazione. Cinque, si tratta di un'analisi univoca di stringhe letterali, che è più simile a uno scherzo pratico che a un buon stile di programmazione.
Quanto segue richiede anche uno spreco di istanze:
var fracArray = Array.ConvertAll(numDenArray, item => (Fraction)item);
La seguente uso di una proprietà ha lo stesso problema a meno che non si utilizza quei terribili Jagged array:
public int[2] pair {
set {
numerator = value[0];
denominator = value[1];
}
}
// Then later...
var fracStrings = new int[2,4] {{0,1}, /*etc*/};
var fracArray = new Fraction[fracStrings.Length];
int index = 0;
foreach (int[2,] fracString in fracStrings) {
fracArray[index].pair = fracStrings[index];
}
Questa variazione non impone paia :
foreach (int[,] fracString in fracStrings) {
fracArray[index].pair = fracStrings[index];
}
Ancora una volta, questo approccio è comunque grande.
Queste sono tutte le idee che so come derivare. C'è una buona soluzione?
C'è un [post correlati] (http://stackoverflow.com/questions/23534114/initialization-of-const-array-of-struct), che propone un trucco usando un elenco di oggetti. –
@Axel - Bingo. – MackTuesday