Скажем, у меня есть класс, как это:Элегантная инициализация массива экземпляров класса в 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
}
Я хочу, чтобы инициализировать массив из них в хорошем пути, и этот пост является большой список подходы, подверженные ошибкам или синтаксически громоздкие.
Конечно Конструктор массива было бы хорошо, но нет такой вещи:
public Fraction[](params int[] numbers)
Так что я вынужден использовать метод как
public static Fraction[] CreateArray(params int[] numbers)
{
// Make an array and pull pairs of numbers for constructor calls
}
, которая является относительно неуклюжими, но я не видишь пути вокруг него.
Обе формы подвержены ошибкам, потому что пользователь может ошибочно передать нечетное количество параметров, возможно, потому что он/она пропустил значение, которое оставило бы функцию царапающей голову, задаваясь вопросом, чего действительно хочет пользователь. Это может вызвать исключение, но тогда пользователю нужно будет попробовать/поймать. Я бы предпочел не налагать это на пользователя, если это возможно. Итак, давайте навяжем пары.
public static Fraction[] CreateArray(params int[2][] pairs)
Но вы не можете назвать это CreateArray хорошим способом, как
Fraction.CreateArray({0,1}, {1,2}, {1,3}, {1,7}, {1,42});
Вы не можете даже сделать
public static Fraction[] CreateArray(int[2][] pairs)
// Then later...
int[2][] = {{0,1}, {1,2}, {1,3}, {1,7}, {1,42}};
Fraction.CreateArray(numDenArray);
Обратите внимание, что это будет работать нормально в C++ (Я точно уверен).
Вы вынуждены сделать одно из следующего вместо этого, что является отвратительным. Синтаксис ужасен, и кажется очень неудобным использовать зубчатый массив, когда все элементы имеют одинаковую длину.
int[2][] fracArray = {new int[2]{0,1}, /*etc*/);
Fraction.CreateArray(fracArray);
// OR
Fraction.CreateArray(new int[2]{0,1}, /*etc*/);
Аналогично, кортежи Python стиля являются незаконными и C# версия неприглядное:
Fraction.CreateArray(new Tuple<int,int>(0,1), /*etc*/);
Использование чистого 2D массива может иметь следующий вид, но это незаконно, и я уверен, что нет никакого законного способа выразить это:
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}});
Это не навязывает пары:
public static Fraction[] CreateArray(int[,] twoByXArray)
Хорошо, как насчет
public static Fraction[] CreateArray(int[] numerators, int[] denominators)
Но тогда два массива могут иметь различные длины. C++ допускает
public static Fraction[] CreateArray<int N>(int[N] numerators, int[N] denominators)
но, хорошо, это не C++, не так ли?
Такого рода вещи является незаконным:
public static implicit operator Fraction[](params int[2][] pairs)
и неосуществимым в любом случае, опять-таки из-за отвратительного синтаксисом:
Fraction[] fracArray = new Fraction[](new int[2]{0,1}, /*etc*/);
Это может быть приятно:
public static implicit operator Fraction(string s)
{
// Parse the string into numerator and denominator with
// delimiter '/'
}
Тогда вы возможно
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];
}
Мне не нравится этот подход по пяти причинам. Во-первых, неявный бросок неизбежно создает новый объект, но у нас уже есть отлично, а именно тот, который мы пытаемся инициализировать. Во-вторых, это может ввести в заблуждение. В-третьих, это заставляет вас явно делать то, что я хотел инкапсулировать в первую очередь. Четыре, это оставляет место для плохого форматирования. Пять, это включает в себя разовое разбор струнных литералов, что больше похоже на практическую шутку, чем на хороший стиль программирования.
Следующая также требует расточительного экземпляра:
var fracArray = Array.ConvertAll(numDenArray, item => (Fraction)item);
Следующая использование имущества имеет ту же проблему, если вы не используете эти ужасные рваные массивы:
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];
}
Это изменение не навязывает пары :
foreach (int[,] fracString in fracStrings) {
fracArray[index].pair = fracStrings[index];
}
Опять же, этот подход в любом случае большой.
Это все идеи, которые я знаю, как получить. Есть ли хорошее решение?
Существует [связанный пост] (http://stackoverflow.com/questions/23534114/initialization-of-const-array-of-struct), который предлагает трюк, используя список объектов. –
@Axel - Бинго. – MackTuesday