• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

C# gurus, a question about ArrayLists

RaynorWolfcastle

Diamond Member
I'm having trouble passing a 2-D ArrayList into another class. The snippet of code I'm using is as follows:
class GraphConstruction
{
public GraphConstruction(Graphics grfx, Size size, Point pt)
{
this.grfx = grfx;
this.graphSize = size;
this.graphLocation = pt;
}

public void DisplayIt()
{

ArrayList tempData = new ArrayList();
tempData.Add(new DateTemp(new Date(1,1,1800),10));

ArrayList multTempData = new ArrayList();
multTempData.Add(tempData);


GraphBG grph = new GraphBG(grfx, Color.Black,graphSize, graphLocation);
GraphData gData = new GraphData(grfx, Color.Black, multTempData);
grph.DisplayIt();
gData.DisplayIt();

}
protected Graphics grfx;
protected Size graphSize;
protected Point graphLocation;
}


class GraphData : GraphComponents
{
public GraphData(Graphics grfx, Color clr)
{
this.grfx = grfx;
this.clr = clr;
}

public GraphData(Graphics grfx, Color clr, ArrayList DataPoints)
{
this.clr = clr;
this.grfx = grfx;
this.dataPoints = DataPoints;
}

public override void DisplayIt()
{
grfx.DrawString(dataPoints[0][0].ToString(), new Font("Arial",12), new SolidBrush(Color.Black), 20, 20);
}


private Color clr;
private Graphics grfx;
public ArrayList dataPoints;
}


I omitted a bunch of code that is more or less relevant to this. ToString() is appropriately overriden for the DateTemp class.
the underlined part is what causes the error, the compiler tells me: "Cannot apply indexing with [] to an expression of type object"

The error does not occur if I pass in a 1-D ArrayList and adjust all the code appropriately. Oddly enough, the debugger has no problem showing me the string's value when I monitor the value of dataPoints[0][0].ToString()
Judging by the message, it seems that this is a casting problem, though I have not been able to solve it

If you're wondering what I'm trying to do:
What I want to do is (eventually) allow the user to add as many data series of DateTemps as he wants, I figured that using a 2-D ArrayList would be the best way.

Let me know if you know how I could solve this problem and/or have a suggestion that may help.



As always any help is greatly appreciated,
-Ice

*edited for readability but the forum removes all the tabs so there's only so much I can do 😱
 
Yer problem might be that an array list contains an Object, it might help to cast it back into whatever type you want befoe using it.
 
Wow, Smaug registered just to help you out.

I'm not a C# developer, but I know Java, which is the language C# was modeled upon. Smaug's advice seems appropriate, and I'll elaborate. Since C# does not have templates, indexing an ArrayList returns the Object stored in that list; you'll have to downcast to the proper subtype. If you have nested ArrayLists, you'll have to cast the result of the first indexing into the proper collection type before you can index it. For example:

(( (List) dataPoints[0])[0]).ToString()

And they say LISP has ugly parenthesized syntax. 😉
 
Originally posted by: Smaug
Yer problem might be that an array list contains an Object, it might help to cast it back into whatever type you want befoe using it.

Thank you both very much. I figured that was likely the problem but I couldn't get the syntax right (I didn't find the correct combination of parenthesis, actually)

Smaug, Welcome to the Forums 🙂 I'll give you a 10 rating if you enable profile rating 🙂.

(manly, I'll do the same for you if you like 😉 )

-Ice

 
Originally posted by: icecool83
Originally posted by: Smaug
Nay, just iterate through in a for loop 🙁

or better yet, a foreach loop 😀 Viva C#!

-Ice

So did you manage to cast them all automatically? Will you share the code? I'm interested to see how you did it.
 
unfortunately, there's a technicality that prevented me from using a foreach loop (I had to pass all the points to an array [by reference of course] to make the syntax less cumbersome). Any how I ended up making with nested for loops... no automatic casting 🙁

If you're interested in the code anyway, here it is:
int m,j;
for(m = 0; m < dataPoints.Count; m++)
{
dP[m] = new DateTemp[((ArrayList) dataPoints[m]).Count];
....for(j = 0; j < ((ArrayList) dataPoints[m]).Count; j++)
....{
....dP[m][j] = (DateTemp) ((ArrayList) dataPoints[m])[j];
....}
}

-Ice
 
Originally posted by: joohang

So did you manage to cast them all automatically? Will you share the code? I'm interested to see how you did it.
I don't think you can cast them automatically unless you could override the index operator as in C++.

You can still create your own specialized FooList that implements Foo get(int index) but then you can't use the [ ] notation. In general, I don't mind that much that Java does not have as much expressive power as other languages.

Templates probably would work as well, but Java's generic programming isn't out yet for MS to copy. 😛 Templates in C++ seem massively complicated at times.
 
Originally posted by: manly

I don't think you can cast them automatically unless you could override the index operator as in C++.

You can still create your own specialized FooList that implements Foo get(int index) but then you can't use the [ ] notation. In general, I don't mind that much that Java does not have as much expressive power as other languages.

Templates probably would work as well, but Java's generic programming isn't out yet for MS to copy. 😛 Templates in C++ seem massively complicated at times.

C# Indexers provide similar function to overloading the '[]' operator. However, for what I'll be doing with it, I'll stick with what I've done unless someone has an incredibly better solution 🙂

-Ice
 
Originally posted by: icecool83

C# Indexers provide similar function to overloading the '[]' operator. However, for what I'll be doing with it, I'll stick with what I've done unless someone has an incredibly better solution 🙂

-Ice
Cool, I stand corrected then.

Although I'm a bit puzzled why they needed to create a distinct indexer syntax rather than just allowing overriding the [ ] operator. Either way, the onus is on the programmer to choose to use the feature only where appropriate.
 
Originally posted by: manly
Originally posted by: icecool83

C# Indexers provide similar function to overloading the '[]' operator. However, for what I'll be doing with it, I'll stick with what I've done unless someone has an incredibly better solution 🙂

-Ice
Cool, I stand corrected then.

Although I'm a bit puzzled why they needed to create a distinct indexer syntax rather than just allowing overriding the [ ] operator. Either way, the onus is on the programmer to choose to use the feature only where appropriate.

Actually indexers are quite easy to use and their syntax is in line with properties (which you may or may not be familiar with since I'm not sure whether if there's something equivalent in Java).

-Ice
 
Although I'm a bit puzzled why they needed to create a distinct indexer syntax rather than just allowing overriding the [ ] operator. Either way, the onus is on the programmer to choose to use the feature only where appropriate.

You can override the [] operator, just not directly. Note that both standard properties and indexers are treated as properties in the CLR. These are sometimes called parameterless and parameterful properties, respectively. The use of the this[object o] parameterful property (indexers) syntax is merely one of convenience in C#. The compiler will emit the same IL for parameterful properties as it does for parameterless (standard properties) properties. It emits the following:

- a "get" accessor method. For parameterless properties, the name of this method will be get_PropertyName.
- a "set" mutator method. Same as above; for parameterless properties, the name of this method will be set_PropertyName.
- a property definition in the metadata of the module. This just provides a level of indirection between the get/set methods themselves and the property definition.

So, although you can't technically override the [] operator, you can do whatever is needed within the get/set methods.

Thus, if you define a property like this...

public string Name { get { return name; } set { name = value; } } // please excuse the poor formatting

The compiler will emit two methods: get_Name and set_Name. Properties are first-class in the CLR. What this means is that languages that do not inherently support properties can consume a managed module and simply call the get_Name and set_Name methods directly.

Each get/set method has a "specialname" attribute applied to it's metadata. I don't understand why they chose to do this as it complicates interoperability, and makes it so that languages that don't support properties can only consume them, not create them. If the "specialname" attribute in the metadata wasn't required for consuming languages that support properties to use them as properties, languages that don't support properties could simply create the get_PropertyName and set_PropertyName methods themselves, and other property supporting languages could consume them. Hopefully they'll make this easier in the future.

Everything I noted above is identical to how parameterful properties are treated. Suppose you have this...

public string this[int z] { get { return ""; } set { somecollection[z] = value; } }

This is indeed a parameterful property, and the compiler will emit the same thing as it does with parameterless properties. The only difference is that, by default, the compiler will emit the methods get_Item and set_Item as you haven't named the property. If you look in the FCL, you'll see many classes that have an Item property. This is indicative of a parameterful property, so you can use an indexer. Both methods still have the "specialname" attribute in the metadata, so again that means that consuming languages that don't support parameterful properties can call the get_Item and set_Item methods, they just can't create them 🙁.

Also, you can modify the name that the compiler emits for parameterful properties so that you don't have to use Item as the property. Just use the IndexerName attribute to modify the name the compiler emits. e.g.:

[System.Runtime.CompilerServices.IndexerName("Foo")]
public string this[int z] { get { return ""; } set { somecollection[z] = value; } }

Now, get_Foo and set_Foo will be emitted instead of get_Item and set_Item. The System.String class does this for it's Chars property.

There are so many facets of the CLR that C# simply does not take advantage of. Every syntactical convenience provided in C# is simply an abstraction of facilities provided by the CLR. Fire up ildasm and see what it's really doing; it's actually quite fun. Events were a big conundrum for me until I found out how it really worked by examining the IL and the methods emitted automatically by the compiler.

Once again, I've rambled.

[edit]Remind me not to use 'i' as an indexer when posting code on these forums 🙂[/edit]
 
Descartes 😕 -> I haven't the slightest idea what that post said 😱

Actually, having taught myself OOP and C#, I figured while reading the book that the reason to use properties was for data validation purposes and that indexers were there only for convenience. I guess I had a bit of a naive understanding of it 😱

-Ice
 
Back
Top