Скажем, у меня есть класс вроде этого:
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);
Обратите внимание, что это отлично работает в С++ (я уверен).
Вместо этого вы вынуждены сделать одно из следующих: это отвратительно. Синтаксис ужасен, и кажется неудобным использовать зубчатый массив, когда все элементы имеют одинаковую длину.
int[2][] fracArray = {new int[2]{0,1}, /*etc*/);
Fraction.CreateArray(fracArray);
// OR
Fraction.CreateArray(new int[2]{0,1}, /*etc*/);
Аналогично, кортежи в стиле Python являются незаконными, а версия С# - icky:
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)
Но тогда два массива могут иметь разную длину. С++ позволяет
public static Fraction[] CreateArray<int N>(int[N] numerators, int[N] denominators)
но, ну, это не С++, не так ли?
Это незаконно:
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];
}
Опять же, этот подход в любом случае большой.
Это все идеи, которые я знаю, как вывести. Есть ли хорошее решение?