Indexers

  • Thread starter Thread starter Alvin Bruney
  • Start date Start date
A

Alvin Bruney

In later versions of the framework is it possible to have indexers on
properties for member fields?

Say for example I have

private ArrayList blah;

and a propget

public object Blah[int index]
{
get { return blah[index]; }
}
 
Alvin,
In later versions of the framework is it possible to have indexers on
properties for member fields?

No. But this is a C# language limitation.



Mattias
 
Will it ever be added or is there a good reason for not having this?

Since propertys are methods anyway, I dont see a technicaly reason why they
cannot be permited
 
Alvin,
Will it ever be added or is there a good reason for not having this?

"Ever" is a long time, and since nothing beyond the Whidbey release
has been announced, I don't thing anyone can tell. It probably also
depends on customer demand.

Since propertys are methods anyway, I dont see a technicaly reason why they
cannot be permited

While they technically are implemented that way, I think conceptually
properties and methods are very different.



Mattias
 
In later versions of the framework is it possible to have indexers on
properties for member fields?

Say for example I have

private ArrayList blah;

and a propget

public object Blah[int index]
{
get { return blah[index]; }
}

There is only one thing wrong with the indexer in your code snippet. You
forgot the "this" keyword. Here is a snippet from one of my custom
collection classes...

public class EntityCollection:CollectionBase
{
// "this.List" is an ArrayList that is a member of CollectionBase
public Entity this[int index]
{
get { return (Entity)this.List[index]; }
}
//...<Snip>
}

To access a member of this collection...

EntityCollection ec = new EntityCollection();
ec.Add(...);
Entity e1 = ec[0];

If you want to access a single element from a member collection, then you
should be calling the indexer on that member property... IE.

//A collection of the "Document" class
public class DocumentCollection:CollectionBase{...}
public class Application
{
private DocumentCollection _docs;
public Application(){_docs=new DocumentCollection();}
public DocumentCollection Documents{get{return _docs;}}
}

to access a document of the application...

Application app = new Application();
... add some documents here...
Document doc = app.Documents;

Let me know if you have further questions.

To see how to create a collection like the ones above, use my open source
collection generator/templates found at:
http://sourceforge.net/projects/colcodegen

Michael Lang, MCSD
 
yes but that means I have to refer to it as the class, I could have many
different arrays in a class and I want to use an indexer on more than one.

Methods are the only way it seems.

I was looking for somethin glike a property and an indexer for that kind of
scenario (yes i know properties are just methods anyway)

Michael Lang said:
In later versions of the framework is it possible to have indexers on
properties for member fields?

Say for example I have

private ArrayList blah;

and a propget

public object Blah[int index]
{
get { return blah[index]; }
}

There is only one thing wrong with the indexer in your code snippet. You
forgot the "this" keyword. Here is a snippet from one of my custom
collection classes...

public class EntityCollection:CollectionBase
{
// "this.List" is an ArrayList that is a member of CollectionBase
public Entity this[int index]
{
get { return (Entity)this.List[index]; }
}
//...<Snip>
}

To access a member of this collection...

EntityCollection ec = new EntityCollection();
ec.Add(...);
Entity e1 = ec[0];

If you want to access a single element from a member collection, then you
should be calling the indexer on that member property... IE.

//A collection of the "Document" class
public class DocumentCollection:CollectionBase{...}
public class Application
{
private DocumentCollection _docs;
public Application(){_docs=new DocumentCollection();}
public DocumentCollection Documents{get{return _docs;}}
}

to access a document of the application...

Application app = new Application();
... add some documents here...
Document doc = app.Documents;

Let me know if you have further questions.

To see how to create a collection like the ones above, use my open source
collection generator/templates found at:
http://sourceforge.net/projects/colcodegen

Michael Lang, MCSD
 
yes but that means I have to refer to it as the class, I could have
many different arrays in a class and I want to use an indexer on more
than one.

Methods are the only way it seems.

I was looking for somethin glike a property and an indexer for that
kind of scenario (yes i know properties are just methods anyway)

Michael Lang said:
If you want to access a single element from a member collection, then
you should be calling the indexer on that member property... IE.

//A collection of the "Document" class
public class DocumentCollection:CollectionBase{...}
public class Application
{
private DocumentCollection _docs;
public Application(){_docs=new DocumentCollection();}
public DocumentCollection Documents{get{return _docs;}}
}

to access a document of the application...

Application app = new Application();
... add some documents here...
Document doc = app.Documents;


You can always make the ArrayList public instead of private, or create a public property
that returns that arrayList or a clone of it. If you need more control, or don't want
to waste resources making clones, then I still recommend my previous Documents sample.
Here is a example of making the members public:

======================================================================
using System;
using System.Collections;

namespace IndexerTest2
{
public class MyClass
{
public ArrayList Array1; //publically editable
private ArrayList _array2;

public MyClass()
{
Array1 = new ArrayList();
_array2 = new ArrayList();
_array2.Add("internal add test");
}
public ArrayList Array2
{ //if you don't want it to be editable return a clone.
get{return (ArrayList)_array2.Clone();}
}

[STAThread]
static void Main(string[] args)
{ //Testing code...
MyClass c1 = new MyClass();
c1.Array1.Add("test 1");
Console.WriteLine(c1.Array1[0].ToString());
c1.Array2.Add("test 2"); //does not add to _array2...
Console.WriteLine(c1.Array2[0].ToString());
Console.WriteLine(c1.Array2[1].ToString()); //this line fails
Console.ReadLine();
}
}
}
======================================================================
 
You can do it, but it's more than just an indexer. Basically, you have a
method that returns an ICollection for each of your internal Array lists.
You can write your own private class that implements ICollection and return
it, in case you don't want to allow certain operations, such as Insert,
Remove, Set, etc. The point is, you can control access to your internal
array list, and even strongly type the data.

For a good example, look at how Hashtable lets you access Keys and Values.
There are two properties that both return ICollection that basically give
you two different views of the same data structure. As a result, you can do
hashtable.Keys[0] and hashtable.Items[0]. Even better, you can use
foreach() on these properties.

Here's a skeleton of how you'd do it:

public class MultiCollection {

private SubList list1;
private SubList list2;
private SubList list3;
// so on...

private class SubList : ICollection {

internal ArrayList list;

// implement all other required members, throwing exceptions on
unsupported operations

}

public ICollection Indexer1 {
get {
return list1;
}
}

public ICollection Indexer2 {
get {
return list2;
}
}

// so on...

}

Whether you decide to put the list logic in your private SubList class or in
the container class is up to you. It depends on what you're doing. In the
case of the Hashtable, the sub-lists (Keys and Values) basically hold a
pointer to the parent hashtable and access it's private data directly.


--Matthew W. Jackson


Alvin Bruney said:
yes but that means I have to refer to it as the class, I could have many
different arrays in a class and I want to use an indexer on more than one.

Methods are the only way it seems.

I was looking for somethin glike a property and an indexer for that kind of
scenario (yes i know properties are just methods anyway)

Michael Lang said:
In later versions of the framework is it possible to have indexers on
properties for member fields?

Say for example I have

private ArrayList blah;

and a propget

public object Blah[int index]
{
get { return blah[index]; }
}

There is only one thing wrong with the indexer in your code snippet. You
forgot the "this" keyword. Here is a snippet from one of my custom
collection classes...

public class EntityCollection:CollectionBase
{
// "this.List" is an ArrayList that is a member of CollectionBase
public Entity this[int index]
{
get { return (Entity)this.List[index]; }
}
//...<Snip>
}

To access a member of this collection...

EntityCollection ec = new EntityCollection();
ec.Add(...);
Entity e1 = ec[0];

If you want to access a single element from a member collection, then you
should be calling the indexer on that member property... IE.

//A collection of the "Document" class
public class DocumentCollection:CollectionBase{...}
public class Application
{
private DocumentCollection _docs;
public Application(){_docs=new DocumentCollection();}
public DocumentCollection Documents{get{return _docs;}}
}

to access a document of the application...

Application app = new Application();
... add some documents here...
Document doc = app.Documents;

Let me know if you have further questions.

To see how to create a collection like the ones above, use my open source
collection generator/templates found at:
http://sourceforge.net/projects/colcodegen

Michael Lang, MCSD

 
You can do it, but it's more than just an indexer. Basically, you
have a method that returns an ICollection for each of your internal
Array lists. You can write your own private class that implements
ICollection and return it, in case you don't want to allow certain
operations, such as Insert, Remove, Set, etc. The point is, you can
control access to your internal array list, and even strongly type the
data.

For a good example, look at how Hashtable lets you access Keys and
Values. There are two properties that both return ICollection that
basically give you two different views of the same data structure. As
a result, you can do hashtable.Keys[0] and hashtable.Items[0]. Even
better, you can use foreach() on these properties.

Your general idea is correct. But, I'm guessing you meant to say:

"Basically, you have a property that returns an ICollection for each of
your internal Array lists." (swapped method out for property).

The "Keys" and the "Values" members of hashtable are properties, not
methods. If they were methods they would have parenthesis when you
reference them, IE:

hashtable.Keys()[0] and hashtable.Values()[0]

Also note there is no "Items" property. The "Values" property holds the
hashtable's values. The "Item" (no s), is the property that is also the
indexer for the hashtable, which really just returns items from the
"Values" property of the hashtable.

Kudos on the excellent example. My "documents" example (same idea)
propably should have exposed a second and third sub list property to be as
clear as yours.

Michael Lang, MCSD
 
yes but that means I have to refer to it as the class, I could have
many different arrays in a class and I want to use an indexer on more
than one.
<snip>

Michael Lang said:
<snip>

//A collection of the "Document" class
public class DocumentCollection:CollectionBase{...}
public class Application
{
private DocumentCollection _docs;
public Application(){_docs=new DocumentCollection();}
public DocumentCollection Documents{get{return _docs;}}
}

to access a document of the application...

Application app = new Application();
... add some documents here...
Document doc = app.Documents;


Let me be a little more clear...

public DocumentCollection Documents{get{return _docs;}}

In the line above "Documents" is the property name.
"DocumentCollection" is the type of the property. I could have many
properties that all return a "DocumentCollection" with different names...

public DocumentCollection Documents{get{return _docs;}}
public DocumentCollection Papers{get{return _docs;}}
public DocumentCollection Reports{get{return _docs;}}

Your return type could just as easily by "ArrayList" instead of
"DocumentCollection". As Matthew also noted, you may want to create a
custom collection type instead of returning the raw array. This way you
can add extra validation to limit the types of operations the user of the
"Application" class (as in my example) or the "MultiCollection" class (as
in Matthew's example) can use each of the sub lists. You should do this
even if you don't need the extra validation now. You don't want to
change the interfaces of your components later if it is decided that
validation is needed. This is the same reason it is not recommended you
make public fields, but instead wrap a dummy property get and set around
it at the least.

I hope we've cleared this up for you?

Michael Lang, MCSD
 
hehe.. rushed post

Michael Lang said:
You can do it, but it's more than just an indexer. Basically, you
have a method that returns an ICollection for each of your internal
Array lists. You can write your own private class that implements
ICollection and return it, in case you don't want to allow certain
operations, such as Insert, Remove, Set, etc. The point is, you can
control access to your internal array list, and even strongly type the
data.

For a good example, look at how Hashtable lets you access Keys and
Values. There are two properties that both return ICollection that
basically give you two different views of the same data structure. As
a result, you can do hashtable.Keys[0] and hashtable.Items[0]. Even
better, you can use foreach() on these properties.

Your general idea is correct. But, I'm guessing you meant to say:

"Basically, you have a property that returns an ICollection for each of
your internal Array lists." (swapped method out for property).

The "Keys" and the "Values" members of hashtable are properties, not
methods. If they were methods they would have parenthesis when you
reference them, IE:

hashtable.Keys()[0] and hashtable.Values()[0]

Also note there is no "Items" property. The "Values" property holds the
hashtable's values. The "Item" (no s), is the property that is also the
indexer for the hashtable, which really just returns items from the
"Values" property of the hashtable.

Kudos on the excellent example. My "documents" example (same idea)
propably should have exposed a second and third sub list property to be as
clear as yours.

Michael Lang, MCSD
 
Back
Top