C#中List保存的结构体

前些时间用C#的List保存一些结构体,结果出现问题:在把一个结构A加入到List中后,再修改A中的字段值,结果List中的所有项对应的字段也全都变化了!

结构定义:

public struct xtlist
{
   public uint[] vlist;
}

在本结构中,定义了一个uint数组,目的是产生N个xtlist结构,每个结构中的vlist数量是一样的,项目中用到的是5个,而N是不确定的,至少会大于1

首先会有定义个字符串,格式为5个项,比如
1,2,3,4,5
每一项都是数字,但可以用 a-b 的形式表示一个范围,比如:
1,2-10,3,4,5
这样就要生成9个xtlist结构,每一个中的vlist就是固定5个值,其中的第二项的值就是从2到10,其它项的值分别都是固定的1,3,4,5

入口程序如下:

strLine = "1,2-10,3,4,5";
string[] strField = strLine.Split(',');
List<xtlist> valList = new List<xtlist>();
xtlist valsm;
valsm.vlist = new uint[5];
ParserIntField(ref valList, valsm, strField, 0);

以上代码通过调用自定义函数ParserIntField()来生成N个xtlist结构,根据strLine的值,应该是生成9个。本函数没有问题,问题发生在自定义函数中。代码如下:

void ParserIntField(ref List<xtlist> valList, xtlist valItem, string[] strField, int index)
{
   uint[] iList = GetRangeList(strField[index]);
   int im;
   for (im = 0; im < iList.Length; im++)
   {
     valItem.vlist[index] = iList[im];   // 此行对元素赋值
     if (index + 1 == strField.Length)
     {
       // 到结尾了,就添加了valItem中即可。这行玄机
       valList.Add(valItem);
     }
     else
     {
       ParserIntField(ref valList, valItem, strField, index + 1);
     }
  }
}

其中的GetRangeList()获取对应项的一个值列表,如果是一个数字,则iList就只有一个元素,如果是“2-10”,那就是一个有9个元素的数组。此函数简单,仅仅是查看中间是否有“-”,如果有,则就是一个范围,否则就是一个数字。

ParserIntField()之所以要用递归,因为几个字段中,每一项都是数字,而且这样还可以随便适应N个字段的情况,修改的时候也很容易。

第一趟,获取到的5个数字为: 1,2,3,4,5
第二趟,获取到的5个数字为: 1,3,3,4,5
第三趟,获取到的5个数字为: 1,4,3,4,5
第四趟,获取到的5个数字为: 1,5,3,4,5
第五趟,获取到的5个数字为: 1,6,3,4,5

第九趟,获取到的5个数字为: 1,10,3,4,5

在完成第一趟后,valList中有一个xtlist结构,从第二趟开始,每当到达第二项时,一通过
valItem.vlist[index] = iList[im];
这一行,则valList中的所有结构中vlist中的第二项的值全都变成了最新的iList[im]的值!
从这个现象看出,这个List保存的是一个原来的实例,而不是当调用List.Add()时,其创建的一个新实例,所以如果调用了多次Add()后,其实它们都是同一个实例,所以只要有一个修改,则其它的也都修改。这下麻烦了,唉

为了解决同一个实例的问题,修改Add()的调用位置代码,修改后如下所示:

// 到结尾了,就添加了valItem中即可。这行玄机
xtlist xit = valItem;
valList.Add(xit);

把valItem赋给xit新变量,然后再把xit加入到List中,经过测试,问题没有得到修改,和原始的情况完全一致。
从这个现象看出来,这个赋值,竟然不创建一个新的实例,竟然是同一个实例,晕,这样的话就更麻烦了

如果在加入的位置采用

// 到结尾了,就添加了valItem中即可。这行玄机
xtlist xit = new xtlist();
xit.vlist = new uint[valItem.vlist.Length];
Array.Copy(valItem.vlist, xit.vlist, valItem.vlist.Length);
valList.Add(xit);

这样修改后再测试,问题解决。
但是这样如果xtlist的结构有变化,如果有多个地方采用这种方式使用这个结构,那修改起来就麻烦。为了解决这个维护问题,对xtlist进行了如下的改造:

public struct xtlist
{
   public uint[] vlist;
   public xtlist(xtlist xi)
   {
      if (xi.vlist == null)
         vlist = null;
      else
      {
         int count = xi.vlist.Length;
         vlist = new uint[count];
         for (int i = 0; i < count; i++)
         {
            vlist[i] = xi.vlist[i];
         }
      }
   }
}

然后加入的位置也做相应的修改:

// 到结尾了,就添加了valItem中即可。这行玄机
xtlist xit = new xtlist(valItem);
valList.Add(xit);

这样修改之后,使用的地方简洁多了。至此,问题较好地解决了。

虽然问题解决了,但总是感觉怪怪的。我使用C#的时间非常有限,所以很多不了解,欢迎有经验的C#们留言提供更好的建议,不胜感激!

猜你喜欢

转载自blog.csdn.net/jszj/article/details/73332216