C#:为什么需要使用中间数组来定义交错数组?
C#: Why does an intermediate array need to be used for defining a jagged array?
我在我写的一些我不理解的代码中发现了一个奇怪的效果。我找到了解决方法,但我想知道为什么原始代码无法按预期工作。
所以填充一个交错的数组,我试图单独定义每个单元格。这导致最后定义的数组有 10 个副本。来自这段代码:
for (int i = 0; i < 10; i++)
{
serialisableHighScores.scores[i][0] = _highScores[i].date;
serialisableHighScores.scores[i][1] = _highScores[i].score;
serialisableHighScores.scores[i][2] = _highScores[i].questionsAsked;
}
而当使用一维数组作为中间值时,数据按预期保存。我的意思是锯齿状数组中保存了 10 个独特的数组。来自这段代码:
for (int i = 0; i < 10; i++)
{
int[] scoreArray = { _highScores[i].date, _highScores[i].score, _highScores[i].questionsAsked };
serialisableHighScores.scores[i] = scoreArray;
}
原因是交错数组实际上是值数组的数组。
由于数组是对象,引用类型,这意味着如果您构造一个锯齿状数组,其中有 10 个数组的空间,所有这些数组引用都将初始化为 null
。
换句话说:
int[][] a = new int[10][];
a[0][0] = 10;
抛出 NullReferenceException
.
代码可以这样想:
int[][] a = new int[10][];
int[] temp = a[0]; // this works, but temp is now null
temp[0] = 10; // throws NullReferenceException
要么将一个完全填充的数组分配到第一个槽中,要么分配一个没有值的初始化数组,如下所示:
for (int i = 0; i < 10; i++)
{
serialisableHighScores.scores[i] = new int[3];
serialisableHighScores.scores[i][0] = _highScores[i].date;
serialisableHighScores.scores[i][1] = _highScores[i].score;
serialisableHighScores.scores[i][2] = _highScores[i].questionsAsked;
}
现在,这就是为什么它会在您这边崩溃的原因。您可用的最佳选择是不要使用这样的数组,即不要使用二维数组来保留一个相关值列表,而是使用对象:
public class Score
{
public Score(DateTime date, int score, int questionsAsked)
{
Date = date;
Score = score;
QuestionsAsked = questionsAsked;
}
public DateTime Date { get; }
public int Score { get; }
public int QuestionsAsked { get; }
}
此外,数组适用于固定大小的事物,但通常使用列表通常更好:
var serializableHighScores = new List<Score>();
for (int i = 0; i < 10; i++)
{
serializableHighScores.Add(new Score(_highScores[i].date, _highScores[i].score, _highScores[i].questionsAsked));
}
虽然 给出了变量的名称,但如果您需要使用一些设计糟糕的(我认为)序列化格式的数组,那么最好坚持使用您的代码。
我在我写的一些我不理解的代码中发现了一个奇怪的效果。我找到了解决方法,但我想知道为什么原始代码无法按预期工作。
所以填充一个交错的数组,我试图单独定义每个单元格。这导致最后定义的数组有 10 个副本。来自这段代码:
for (int i = 0; i < 10; i++)
{
serialisableHighScores.scores[i][0] = _highScores[i].date;
serialisableHighScores.scores[i][1] = _highScores[i].score;
serialisableHighScores.scores[i][2] = _highScores[i].questionsAsked;
}
而当使用一维数组作为中间值时,数据按预期保存。我的意思是锯齿状数组中保存了 10 个独特的数组。来自这段代码:
for (int i = 0; i < 10; i++)
{
int[] scoreArray = { _highScores[i].date, _highScores[i].score, _highScores[i].questionsAsked };
serialisableHighScores.scores[i] = scoreArray;
}
原因是交错数组实际上是值数组的数组。
由于数组是对象,引用类型,这意味着如果您构造一个锯齿状数组,其中有 10 个数组的空间,所有这些数组引用都将初始化为 null
。
换句话说:
int[][] a = new int[10][];
a[0][0] = 10;
抛出 NullReferenceException
.
代码可以这样想:
int[][] a = new int[10][];
int[] temp = a[0]; // this works, but temp is now null
temp[0] = 10; // throws NullReferenceException
要么将一个完全填充的数组分配到第一个槽中,要么分配一个没有值的初始化数组,如下所示:
for (int i = 0; i < 10; i++)
{
serialisableHighScores.scores[i] = new int[3];
serialisableHighScores.scores[i][0] = _highScores[i].date;
serialisableHighScores.scores[i][1] = _highScores[i].score;
serialisableHighScores.scores[i][2] = _highScores[i].questionsAsked;
}
现在,这就是为什么它会在您这边崩溃的原因。您可用的最佳选择是不要使用这样的数组,即不要使用二维数组来保留一个相关值列表,而是使用对象:
public class Score
{
public Score(DateTime date, int score, int questionsAsked)
{
Date = date;
Score = score;
QuestionsAsked = questionsAsked;
}
public DateTime Date { get; }
public int Score { get; }
public int QuestionsAsked { get; }
}
此外,数组适用于固定大小的事物,但通常使用列表通常更好:
var serializableHighScores = new List<Score>();
for (int i = 0; i < 10; i++)
{
serializableHighScores.Add(new Score(_highScores[i].date, _highScores[i].score, _highScores[i].questionsAsked));
}
虽然 给出了变量的名称,但如果您需要使用一些设计糟糕的(我认为)序列化格式的数组,那么最好坚持使用您的代码。