Interfaces and Enumerators


T

tshad

A couple of questions on interfaces.

I am looking at interfaces and at an example program I found.

To set up a custom collection you must have IEnumerable and IEnumerator
implemented.

My code is:
**********************************************************************
using System;
using System.Collections;
namespace CustomCollection
{
internal class MyClass
{
public string Name;
public int Age;

//Default constructor
public MyClass()
{
}

//This parametrised constructor will assign value to this class data
members.
public MyClass(string name, int age)
{
this.Name = name;
this.Age = age;
}

}

public class Iterator : IEnumerator, IEnumerable
{
// Instantiating a collection of MyClass type.
private MyClass[] ClassArray;
int Cnt;

public Iterator()
{
//Assigning values in default constructor
ClassArray = new MyClass[4];
ClassArray[0] = new MyClass("Kith", 23);
ClassArray[1] = new MyClass("Smith", 30);
ClassArray[2] = new MyClass("Geo", 19);
ClassArray[3] = new MyClass("Greg", 14);

}

//Defanision for IEnumerator.Reset() method.
public void Reset()
{

Cnt = -1;
}

//Defanision for IEnumerator.MoveNext() method.
public bool MoveNext()
{
return (++Cnt < ClassArray.Length);

}

//Defanision for IEnumerator.Current Property.
public object Current
{
get
{
return ClassArray[Cnt];
}
}
//Defanision for IEnumerable.GetEnumerator() method.
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}

static void Main()
{

IEnumerator temp;

//Now this instance will contain a collection of MyClass Tyes
Iterator It = new Iterator();
//Am trying to access like normal array
foreach (MyClass MY in It)
{
temp = It.GetEnumerator();

Console.WriteLine("Name : " + MY.Name.ToString());
Console.WriteLine("Age : " + MY.Age.ToString());

}
Console.Read();
}

}
}
**********************************************************************

I understand how it works but I am curious why you need the ": IEnumerable"
on my Iterator class.

If I change the line to the following:

public class Iterator : IEnumerator

It works fine without it since I have all the methods implemented.

So what is the point in having it there?

The only reason I think I need IEnumerator there is because I am passing
back an object of type "IEnumerator" and if it wasn't there, Iterator
wouldn't be of type IEnumerator - even though the GetEnumerator() method is
implemented.

If I don't have it there, I get an error on the return statement of
GetEnumerator() saying that

Unable to cast object of type 'CustomCollection.Iterator' to type
'System.Collections.IEnumerator'.

I assume that if I weren't returning an IEnumerator - this wouldn't be
needed, either - just the method.

Thanks,

Tom
 
Ad

Advertisements

P

Peter Duniho

tshad said:
A couple of questions on interfaces.

I am looking at interfaces and at an example program I found.

To set up a custom collection you must have IEnumerable and IEnumerator
implemented.

[...]
I understand how it works but I am curious why you need the ": IEnumerable"
on my Iterator class.

You need your class to implement IEnumerable if and only if you want to
use an instance of your class in situations where an instance of
IEnumerable is expected. For example, as the source collection in a
"foreach" statement.
If I change the line to the following:

public class Iterator : IEnumerator

It works fine without it since I have all the methods implemented.

Removing an interface name from the class declaration won't hinder the
rest of the declaration of the class, unless you have implemented that
interface explicitly. The place where it matters is the code that
_uses_ that class.
So what is the point in having it there?

The only reason I think I need IEnumerator there is because I am passing
back an object of type "IEnumerator" and if it wasn't there, Iterator
wouldn't be of type IEnumerator - even though the GetEnumerator() method is
implemented.

Well, sort of. That's an example of code that depends on your class
implementing IEnumerator, so yes…that's the mechanical reason for having
it. But the true reason for having IEnumerator is that you actually
want a specific class to provide the implementation of IEnumerator.

And really, it doesn't make sense for a class to implement both
IEnumerable and IEnumerator. A class implementing IEnumerable generally
needs to be able to return a fresh instance of the related IEnumerator
each time the GetEnumerator() method is called. In your code example,
every call to GetEnumerator() returns the same instance, and so each
client of the IEnumerator is affected by every other client.

In single-threaded code, where you only ever use IEnumerable via a
"foreach" (and thus never have direct access to the IEnumerator
reference), this can be okay. But in any other context, it's a serious
problem.

It seems to me that you really have two different questions. The first
has to do with the reasons for using interfaces generally, independent
of any specific interface. The second has to do with the enumeration
interfaces specifically. IMHO, you should focus on one at a time.

Finally, I'll point out that while the non-generic IEnumerable and
IEnumerator interfaces are fine for practice and gaining experience, but
in a real-world situation you definitely should be using the generic
IEnumerable<T> and IEnumerator<T> interfaces.

Pete
 
T

tshad

Peter Duniho said:
tshad said:
A couple of questions on interfaces.

I am looking at interfaces and at an example program I found.

To set up a custom collection you must have IEnumerable and IEnumerator
implemented.

[...]
I understand how it works but I am curious why you need the ":
IEnumerable" on my Iterator class.

You need your class to implement IEnumerable if and only if you want to
use an instance of your class in situations where an instance of
IEnumerable is expected. For example, as the source collection in a
"foreach" statement.

Right.

But you don't need the work IEnumerable on the class to use foreach. You
just have to have the methods it defines.

I wasn't concerned about what they do, just why in one case you have to have
the name on the class line and in the other you don't and I think I
understand it. I was only using IEnumerable and IEnumerator as examples of
what I was trying to understand.

In both cases, whether you have the name or not on the class line, they are
implemented. Meaning all the methods are defined. The contract if
fulfilled. But there is a difference between whether something is
implemented and something is a type.

In the case of IEnumerable, I am not using it as a type, i.e.:

public IEnumerable something();

In IEnumerable, I only have to make sure all the methods are there -
implemented. Having the name on the class is superfluous. You can have it
or not. It doesn't help or hurt you.

In the case of IEnumerator, you also have to implement all the methods and
if you weren't going to use it as a type, you wouldn't need the name either.

But since, you are - in the case of:

public IEnumerator GetEnumerator()

having to pass back a type of IEnumerator, that means you have to name it.
The fact that it has all the methods of the same name as the interface
requires doesn't mean the object is of that type - just that it has all the
methods it needs. But when you name it, it is now of that type.

This was what confused me on the matter of interfaces.

If you were always going to use the class name as your type and never the
interface name, the only reason to have it (it seems) is to force the use of
certain method, which I understand.

But if you are the only one who is going to use it and you are not going to
pass it as a type, you just have to make sure all the methods necessary are
there without creating an interface object.

In asp.net, your main page inherits from the Page class and has a gazillion
methods and properties.

If you want to access some of the controls from another page/class and you
don't want to pass each control, you have to pass the page class or create
an interface that has all the objects you want access to and pass that.

For example:

If I have an interface with my controls on them:

public interface IStatusDisplay
{
string Status { get; set; }
string StatusBar { get; set; }
string StatusBar2 { get; set; }
string StatusBar3 { get; set; }
}

And my page class is:

class Something: IStatusDisplay
{
...
}

I can have another page get access to my statusbar on my main page by
passing the interface type:

public static void GetSomething(IStatusDisplay display).

but I could just as easily have passed the class name and not created the
interface:

public static void GetSomething(Something display)

In both case, I would have access to the statusbar, but if I pass the class
instead of the interface I also get access to all the objects, methods and
properties on that page. For coding, the intellisense is easier to use with
the interface as you only see about 10 things and if you pass the class you
see a ton of things and finding what you want would be more difficult.

My point was (long way around), in some cases you want the interface if you
are going to create a "type". But you don't need the interface on the class
if you just need the implementation (I think).
Removing an interface name from the class declaration won't hinder the
rest of the declaration of the class, unless you have implemented that
interface explicitly. The place where it matters is the code that _uses_
that class.

What do you mean implementing it explicitly?
Well, sort of. That's an example of code that depends on your class
implementing IEnumerator, so yes…that's the mechanical reason for having
it. But the true reason for having IEnumerator is that you actually want
a specific class to provide the implementation of IEnumerator.

And really, it doesn't make sense for a class to implement both
IEnumerable and IEnumerator. A class implementing IEnumerable generally
needs to be able to return a fresh instance of the related IEnumerator
each time the GetEnumerator() method is called. In your code example,
every call to GetEnumerator() returns the same instance, and so each
client of the IEnumerator is affected by every other client.
I wasn't really concerned with both being implemented in the same class,
just why one name was needed and the other wasn't.
In single-threaded code, where you only ever use IEnumerable via a
"foreach" (and thus never have direct access to the IEnumerator
reference), this can be okay. But in any other context, it's a serious
problem.

It seems to me that you really have two different questions. The first
has to do with the reasons for using interfaces generally, independent of
any specific interface. The second has to do with the enumeration
interfaces specifically. IMHO, you should focus on one at a time.

Finally, I'll point out that while the non-generic IEnumerable and
IEnumerator interfaces are fine for practice and gaining experience, but
in a real-world situation you definitely should be using the generic
IEnumerable<T> and IEnumerator<T> interfaces.
Not sure why we use one over the other but I know they aren't
interchangeable.

Thanks,

Tom
 
Ad

Advertisements

P

Peter Duniho

tshad said:
But you don't need the work IEnumerable on the class to use foreach. You
just have to have the methods it defines.

True. But that's a very special case, where at compile time the
compiler is doing extra work to handle it. There are lots of examples
in the .NET API where you really do need an IEnumerable implementation
to take advantage of the API (the System.Linq.Enumerable class being a
primary example).
I wasn't concerned about what they do, just why in one case you have to have
the name on the class line and in the other you don't and I think I
understand it. I was only using IEnumerable and IEnumerator as examples of
what I was trying to understand.

In both cases, whether you have the name or not on the class line, they are
implemented.

Wrong. An interface is only implemented if it's declared as being
implemented in the class. Otherwise, to use the class members that
would otherwise be part of the interface, you have to do so explicitly,
using the original type declared for the class. And then you're not
using the interface, you're using the original type of the class.
Meaning all the methods are defined. The contract if
fulfilled. But there is a difference between whether something is
implemented and something is a type.

No. An interface cannot be considered to be implemented unless it's
actually part of the type declaration.
In the case of IEnumerable, I am not using it as a type, i.e.:

public IEnumerable something();

In IEnumerable, I only have to make sure all the methods are there -
implemented. Having the name on the class is superfluous. You can have it
or not. It doesn't help or hurt you.

Very very wrong. Only in very specific, narrow cases can you get away
without declaring the type as implementing the interface, and of those
cases, only the "foreach" has compile-time support. Every other example
uses reflection and would have significantly higher overhead as compared
to if the type is declared as implementing the interface.

It _definitely_ hurts you to implement the members of an interface
without declaring the type as implementing the interface.
In the case of IEnumerator, you also have to implement all the methods and
if you weren't going to use it as a type, you wouldn't need the name either.

But the only way to use IEnumerator is to use it as a type. Otherwise,
there's no point in implementing IEnumerator. You can, of course, write
code that uses your actual class type and calls the MoveNext(), Current,
etc. explicitly, but in that case you're not using IEnumerator. You're
just using your class.

And no code other than code you've written will be able to use the
members that would have been an implementation of IEnumerator, had the
class been declared to implement IEnumerator.
But since, you are - in the case of:

public IEnumerator GetEnumerator()

having to pass back a type of IEnumerator, that means you have to name it.
The fact that it has all the methods of the same name as the interface
requires doesn't mean the object is of that type - just that it has all the
methods it needs. But when you name it, it is now of that type.

This was what confused me on the matter of interfaces.

I think you are confused about why they are used. Simply implementing
the members of an interface does not generally suffice. You are further
confused because you chose to use as your example the IEnumerable
interface, which has a very specific, special-case handling in the C#
compiler, that makes it completely different from the way any other
interface is used.

It's a really poor example to use if you're trying to learn how
interfaces really work.
If you were always going to use the class name as your type and never the
interface name, the only reason to have it (it seems) is to force the use of
certain method, which I understand.

The problem with that approach is that the whole point of using
interfaces is so that your class instance can be used with code that has
never seen your class name.

Suggesting that interfaces are "optional" simply because you could in
fact just use the actual class type as the type to call your instance
misses the point, because that's exactly not the scenario that
interfaces are needed for.

It's like you're saying "interfaces are optional, because I only am
required to use them in situations where I'm required to use them".
But if you are the only one who is going to use it and you are not going to
pass it as a type, you just have to make sure all the methods necessary are
there without creating an interface object.

Even within your own code, it can be advantageous to use interfaces,
specifically so that you can avoid making all of your code dependent on
all of the rest of your code. It's a very useful form of abstraction
that reduces or eliminates dependencies between different code components.
[...]
What do you mean implementing it explicitly?

http://msdn.microsoft.com/en-us/library/ms173157.aspx

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top