c# - C#中类实例数组的优雅初始化

标签 c# arrays initialization

关闭。这个问题是opinion-based .它目前不接受答案。












想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题.

2年前关闭。




Improve this question




假设我有一个这样的类(class):

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# 版本是 icky:
Fraction.CreateArray(new Tuple<int,int>(0,1), /*etc*/);

纯二维数组的使用可能采用以下形式,但这是非法的,而且我确信没有合法的方式来表达它:
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];
}

同样,无论如何,这种方法都很重要。

这些都是我知道如何推导出来的想法。有没有好的解决办法?

最佳答案

我想不出一个优雅的,同时内存高效的数组解决方案。

但是对于使用 C# 6 collection initializer 的列表(和类似的)有一个优雅的解决方案。特征:

public static class Extensions
{
    public static void Add(this ICollection<Fraction> target, int numerator, int denominator)
    {
        target.Add(new Fraction(numerator, denominator));
    }
}

使用该扩展方法,您可以轻松初始化 Fraction list 例如:
var list = new List<Fraction> { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } };

当然,虽然内存效率不高,但您可以使用它来初始化 Fraction数组或者:
var array = new List<Fraction> { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } }.ToArray();

甚至通过使用隐式数组转换运算符声明一个列表派生类来使其更加简洁:
public class FractionList : List<Fraction>
{
    public static implicit operator Fraction[](FractionList x) => x?.ToArray();
}

然后使用
Fraction[] array = new FractionList { { 0, 1 }, { 1, 2 }, { 1, 3 }, { 1, 7 }, { 1, 42 } };

关于c# - C#中类实例数组的优雅初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36736372/

相关文章:

c# - 手动加载框架元素

c# - 执行发布时将 jQuery 对象映射到 C# 类

java - 修复java中的nullpointerException错误

java - 应用程序初始化的首选方式

c++ - 将文本读入字符串与直接用文本初始化字符串

c# - 更改 Web Api 2 Post 方法以接受修改后的正文

c# - 从Core(Portable)调用放置在Droid项目中的方法

java - 我可以在父类(super class)的数组上调用子类吗?

php - 亚马逊 MWS : Accessing Array of Matching Products

swift - 类中属性的初始化,具体是惰性属性?