c# ArrayLists and classes problem

Started by
6 comments, last by snotty 20 years, 1 month ago
I''m writing some test console apps in c# while I learn it, but I''ve run across a situation that is baffling me... If I run this code - using System; using System.Collections; public class Car { public int Speed; public int Direction; } public class DataArrays { public static ArrayList arrCars = new ArrayList(); } class Exercise4 { static void Main() { Car testCar = new Car(); Car testCar2 = new Car(); Car testCar3 = new Car(); testCar.Speed = 40; testCar.Direction = 340; DataArrays.arrCars.Add(testCar); testCar2.Speed = 200; testCar2.Direction = 355; DataArrays.arrCars.Add(testCar2); Console.WriteLine (DataArrays.arrCars.Count); testCar3 = (Car) DataArrays.arrCars[0]; Console.WriteLine (testCar3.Speed); Console.WriteLine (testCar3.Direction); testCar3 = (Car) DataArrays.arrCars[1]; Console.WriteLine (testCar3.Speed); Console.WriteLine (testCar3.Direction); } } Then the output is 2 40 340 200 355 Which is correct. However, if I run - using System; using System.Collections; public class Car { public int Speed; public int Direction; } public class DataArrays { public static ArrayList arrCars = new ArrayList(); } class Exercise4 { static void Main() { Car testCar = new Car(); Car testCar2 = new Car(); testCar.Speed = 40; testCar.Direction = 340; DataArrays.arrCars.Add(testCar); testCar.Speed = 200; testCar.Direction = 355; DataArrays.arrCars.Add(testCar); Console.WriteLine (DataArrays.arrCars.Count); testCar2 = (Car) DataArrays.arrCars[0]; Console.WriteLine (testCar2.Speed); Console.WriteLine (testCar2.Direction); testCar2 = (Car) DataArrays.arrCars[1]; Console.WriteLine (testCar2.Speed); Console.WriteLine (testCar2.Direction); } } The output is 2 200 355 200 355 Which is incorrect. Or, rather, is not what I want it to be! The difference between the two programs is the use of an extra Car object used to add the second element to the array, but I fail to see why re-using the same Car object doesn''t work (i.e. the values held in it seem to be setting both entries in the array to the same values the second time it is used). What really obvious problem am I missing? Btw, I know that the programs aren''t decent OO design, it''s just a bit of experimentation while I learn...
Advertisement
In C# classes are reference types. When you add the class to the array, you only add a refernce to the object. When modifying the same old reference you work on the same object you added to the array previously.
Look up the difference between ''reference''(class) and ''value''(struct) types.

If you know c++, you should consider that a ''class'' type is always treated like a pointer.
Thanks for the advice.

I replaced ''public class Car'' with ''public struct Car'' and it now works as I wanted it to.

I come from a VB background, and what I was trying to do was implement the equivalent of a variable length array of a user defined type.

''Programming C#'' says ''The consensus view is that you ought to use structs only for types that are small, simple, and similar in their behavior and characteristics to built-in types.''
This seems suitable for the case of my sample program, but I''m not sure how complicated the Car struct/class could be before it becomes unsuitable.
Also, structs are referred to as being boxed when referenced, and this must surely lead to a loss of efficiency...

The moral of the story is probably to use a proper OO design rathe than trying to emulate my old VB one!
If I need to create a reference to a sturcture instance, as I would do in cpp below:
Struct1 g = &myotherinstance//g will modify the contents of myotherinstance.


How do I do this in C# if I need to use a struct and just once, i need to make a reference...
GraphicsWare|RenderTechhttp://www.graphicsware.com3D Graphics & Solutions
Thinking further about this issue, I''ve amended the code to the following (the array list is moved into main) -

using System;using System.Collections;public class Car	{	public int Speed;	public int Direction;	}class Exercise4	{	static void Main()		{		ArrayList arrCars = new ArrayList();						Car testCar = new Car();		Car testCar2 = new Car();		testCar.Speed = 40;		testCar.Direction = 340;		arrCars.Add(testCar);		testCar.Speed = 200;		testCar.Direction = 355;		arrCars.Add(testCar);				Console.WriteLine (arrCars.Count);				testCar2 = (Car) arrCars[0];		Console.WriteLine (testCar2.Speed);		Console.WriteLine (testCar2.Direction);		testCar2 = (Car) arrCars[1];		Console.WriteLine (testCar2.Speed);		Console.WriteLine (testCar2.Direction);		}		} 


Now, consider if the car class was really complicated, with a couple of hundred member variables. It would seem that an ideal way of building up the arrCars array list (say, reading a variable number of them in from a data file) would be to use a single Car in a loop - the contents of it could be set and then it is added to the array in one lump with .Add. The same Car would then be used for the next entry read in from the file.
But, as a class is a reference type, the only thing held in the arrCars array is a reference to the Car variable, and so using the same Car variable for all the array entries would result in all the arrCars instances being references to the single Car used for the input processing.
As there could be an indeterminate number of input cars, then having a separate Car variable for each entry starts becoming unworkable (or does it...?)

So how the flip do I go about building up an ArrayList with classs instances in it?

The alternative is to have car as a struct instead of a class, but everything I''ve read says that it is a best for larger objects to be classes and only simple ones be structs.
(And don''t get me started on how I can''t seem to include an array inside a struct definition and get it working - that can a question for another day! Sometimes I think learning c++ instead of c# from scratch would have been easier...)
Take your one car variable, and call new many times. For example,

for(int i = 0; i != 5; i ++){    Car testCar = new Car();    Car.Speed = 40;    MyArrayList.Add(testCar);} 


Once the reference is added to the list, you can use the 'new' keyword again to create a new reference independent of the first.

[edited by - rotos on February 22, 2004 10:03:22 AM]
Great.
I think that''ll do exactly what I want.

My thinking was that resetting the temporary Car wouldn''t work because the reference to it held in the array would still point to it, but it looks like when the new happens then the instance held in the array will still exist, somewhere other than the temporary Car, to be pointed at.

This topic is closed to new replies.

Advertisement