C#结构化列表

时间:2013-07-06 18:44:27

标签: c# list struct

我遇到了这段代码的问题

我有这个结构

public struct bounds
{
        public int xmax = 0;
        public int xmin = 0;
        public int ymax = 0;
        public int ymin = 0;        
};

我从中列出了一个列表

List<bounds> map = new List<bounds>(); 

我试图将空间(或对象)的边界存储在2D数组中(其xmax,xmin,ymin和ymax)我有这个整数y变量,当它到达时它将是一个数字这段代码,但是我的列表“map”下面的代码下面一直有红线(i和j是通过2D数组的计数器)

if(!(map.Contains(y)))  //if the list doesn't already have this number
{    
   map.Add(y);
   map[y].xmax = i;    //and set its xmax, xmin, ymax, ymin
   map[y].xmin = i;
   map[y].ymax = j;
   map[y].ymin = j;
}

if(map[y].xmax < j)     // if its already in the list look at the current 
   map[y].xmax = j;    //  boundaries and decide if new ones should be set

if(map[y].xmin > j)
   map[y].xmin = j;

if (map[y].ymax < j)
    map[y].ymax = i;

if(map[y].ymin > j)
   map[y].ymin = i;

3 个答案:

答案 0 :(得分:3)

原因是struct是一个值类型。

当您从列表中读出结构时,您正在获取副本

因此,这行代码(以及所有类似代码):

map[y].xmax = i;

正在修改您从列表中获得的副本

您可以通过手动检索副本,修改副本并将其放回列表来解决此问题。

注意:Mutable结构会产生各种各样的问题。你遇到的问题只是其中之一,但你不应该让它们变得可变。

另请注意:您使用struct值本身作为列表中的索引器,我认为这是一个错误,并且您实际上正在使用索引变量,否则您真的遇到问题。

这里是一般性提示。如果Visual Studio在您的代码下绘制红色波浪形,您可以将鼠标悬停在它上面以获得工具提示,告诉您出了什么问题。它可能会让你神秘,但错误信息可以更容易用Google搜索:

example of red squigglies

答案 1 :(得分:0)

要使用List索引器,您需要传递一个int。你在这里传递bounds结构

map[y].xmax = i;

y必须是一个表示您要访问的索引的int。我猜y是一个边界结构,因为你已经使用了

map.Add(y);

您的map类型为List<bounds>

答案 2 :(得分:0)

如果数据类型的目的是封装一组固定的相关但独立的值(例如点的坐标),则暴露字段结构比任何其他数据类型更好地满足该描述。除了ToString()Equals()GetHashCode()的覆盖之外,此类结构不应包含许多实例方法;结构使用静态实用程序方法通常比实例方法更好。例如,这将是有问题的:

public void UpdateRange(Point pt)
{
   if (pt.X > xmax) xmax = pt.X;
   if (pt.Y > ymax) ymax = pt.Y;
   if (pt.X < xmin) xmin = pt.X;
   if (pt.Y < ymin) ymin = pt.Y;
}

但这不会:

public void UpdateRange(ref bounds it, Point pt)
{
   if (pt.X > it.xmax) it.xmax = pt.X;
   if (pt.Y > it.ymax) it.ymax = pt.Y;
   if (pt.X < it.xmin) it.xmin = pt.X;
   if (pt.Y < it.ymin) it.ymin = pt.Y;
}

请注意,当类公开结构类型的属性时,无法直接修改此类属性。人们不能使用类似的东西:

bounds.UpdateRange(ref myList[4], newPoint);

也不是,如果UpdateRange是一个实例方法,可以使用:

myList[4].UpdateRange(newPoint);

在后一种情况下,代码会编译,但不起作用。相反,必须使用类似的东西:

var temp = myList[4];
bounds.UpdateRange(ref temp, newPoint);
mylist[4] = temp;

请注意,实例方法和带有ref参数的静态方法在两者都将编译的情况下在语义上是相同的。它们之间的区别在于带有ref参数的静态方法仅在ref参数是可修改变量的情况下编译,但在属性上调用实例方法将导致编译器复制该参数属性为临时变量,在其上调用实例方法,并丢弃结果。

我建议你的类型几乎是一个应该是结构的完美例子。如果它是一个可变类类型,则不清楚何时传递对实例的引用的代码确实传递了实例在调用时发生的瞬时值,或者是否将引用传递给“实时”实体。使用不可变类类型或所谓的不可变结构类型[请注意,实际上没有任何不可变值类型]会使UpdateRange这样的方法编写和运行速度变慢,而不提供特定益处。

关于结构类型需要注意的一个基本要素是每个字段(例如xmin)除了“存储在”xmin“中的内容的最后一个值之外没有任何意义,如果没有存储任何内容则为零如果代码将256写入xmin而-234写入xmax,那么xmin将保留256和xmax -234. Any code which takes a边界`并且应该为此类值做任何准备就像将这些字段作为四个独立的参数一样。