DebareDaDauntless
DebareDaDauntless

Reputation: 521

C# Structured List

I am having problems with this bit of code

I have this structure

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

and I make a list out of it

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

I am trying to store the boundaries of a space (or object) in a 2D array (its xmax, xmin, ymin, & ymax) I have this integer y variable which is going to be some number when it gets to this code, but I keep getting red lines under the code associated with my list "map" (i and j are counters for going through the 2D array)

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;

Upvotes: 0

Views: 327

Answers (3)

supercat
supercat

Reputation: 81105

If the purpose of a data type is to encapsulate a fixed set of related but independent values (such as the coordinates of a point), an exposed-field structure meets that description better than any other data type. Such structures should not have many instance methods other than overrides of ToString(), Equals(), and GetHashCode(); it's generally better for structures to use static utility methods than instance methods. For example, this would be problematical:

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;
}

but this would not:

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;
}

Note that when classes expose properties of a structure type, it is not possible to modify such properties directly. One cannot use something like:

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

nor, if UpdateRange were an instance method, could one use:

myList[4].UpdateRange(newPoint);

In the latter situation, the code would compile, but wouldn't work. Instead, one has to use something like:

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

Note that the instance method and the static method with a ref parameter are semantically identical in the cases where both will compile. The difference between them is that the static method with a ref parameter will only compile in cases where the ref parameter is a modifiable variable, but calling the instance method on a property will cause the compiler to copy that property to a temporary variable, call the instance method on that, and discard the result.

I would suggest that your type is almost a perfect example of something that should be a structure. If it were a mutable class type, it would be unclear when code which passed a reference to an instance was really passing the instantaneous values the instance happened to hold at the time of a call, or was passing a reference to a "live" entity. Using an immutable class type or a so-called immutable struct type [note that there isn't really any such thing as an immutable value type] would make methods like UpdateRange slower to write and to run, while offering no particular benefit.

The one essential thing to note about the structure type is that each field (e.g. xmin) has no meaning other than "the last value that something stored in "xmin", or zero if nothing has been stored there yet. If code writes 256 to xmin and -234 to xmax, then xmin will hold 256 and xmax -234. Any code which takes abounds` and does anything with it should be prepared for such values just as it would be if it took those fields as four separate parameters.

Upvotes: 0

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391286

The reason for this is a struct is a value type.

When you're reading out the struct from the list, you're getting a copy.

As such, this line of code (and all that looks like it):

map[y].xmax = i;

is modifying the copy you got out from the list.

You can counter this by manually retrieving the copy, modifying it, and placing it back into the list.

Note: Mutable structs generates all sorts of problems. The problem you're having is just one of them, but you should not make them mutable.

Also note: You're using the struct value itself as an indexer into the list, I assume this is an error, and that you're actually using an index variable, otherwise you're really having problems.

Here's a general tip though. If Visual Studio is drawing red squigglies under your code, you can hover the mouse over it to get a tooltip telling you what is wrong. It may cryptic to you, but the error message can be googled much easier:

example of red squigglies

Upvotes: 3

keyboardP
keyboardP

Reputation: 69362

To use the List indexer, you need to pass an int. You're passing a bounds struct here

map[y].xmax = i;

y has to be an int representing the index you want to access. I'm guessing y is a bounds struct because you've used

map.Add(y);

and your map is of type List<bounds>.

Upvotes: 0

Related Questions