假设我有一个像这样的类:
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#中是不合法的,而且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];
}
再次强调,这个方法无论如何都很重要。
这些都是我知道的所有想法。有没有一个好的解决方案呢?