Generics, IEnumerable and Polymorphism

M

Mike

It looks to me that in using that in creating generic IEnumerables, you
lose polymorphic capabilities.

Consider this pseudo code:

abstract class BaseClass;

class DerivedClassSpecialFunction1 : BaseClass
class DerivedClassSpecialFunction2 : BaseClass

class Function1ImplementationA : DerivedClassSpecialFunction1
class Function1ImplementationB : DerivedClassSpecialFunction1


List<BaseClass> mylist = new List<BaseClass>

// assume the above list gets populated with a mix of the above classes

foreach (BaseClass item in mylist)
{
DerivedClassSpecialFunction1 derivedItem = item as
DerivedClassSpecialFunction1;

if (derivedItem != null)
{
derivedItem.CallSpecialFunction();
}
}

This allows me to iterate through a list of objects all subclassed from
the same absrtact class and then, for only specific types, call some
function. The function called is the correct function for the instance
type.

I then tried to create an IEnumerator method to try to clean this up a
bit (hoping to avoid testing for the right type everytime (and also
checking for null).

My iterator looked something like this:

public IEnumerator<DerivedClassSpecialFunction1>
GetSpecialFunction1ClassesOnly()
{
foreach (BaseClass item in mylist)
{
if (item is DerivedClassSpecialFunction1) yield return item;
}
}


So, later if I use this enumerator in a foreach call like this:

foreach (DerivedClassSpecialFunction1 item in
GetSpecialFunctionClassesOnly())
{
item.CallSpecialFunction();
}

This does not work correctly. Instead of calling the
Function1ImplementationA version of CallSpecialFunction(), it always
uses the DerivedClassSpecialFunction version.

Is there a way to do what I want and still use custom enumerators? I
want to selectively filter on type, but retain the polymorphic
abilities of subclasses from that type.

Thanks!

Mike
 
M

Mattias Sjögren

Mike,
This does not work correctly. Instead of calling the
Function1ImplementationA version of CallSpecialFunction(), it always
uses the DerivedClassSpecialFunction version.

That's not what I'm seeing. Below is a cleaned up version of your code
that actually compiles. The output is

DerivedClassSpecialFunction1
Function1ImplementationA
Function1ImplementationB

which is what I expect and seems perfectly polymorphic. If you get
something else please post your complete code. Here's mine:

using System;
using System.Collections.Generic;

abstract class BaseClass
{
public virtual void CallSpecialFunction() {
Console.WriteLine("BaseClass"); }
}

class DerivedClassSpecialFunction1 : BaseClass
{
public override void CallSpecialFunction() {
Console.WriteLine("DerivedClassSpecialFunction1"); }
}

class DerivedClassSpecialFunction2 : BaseClass
{
public override void CallSpecialFunction() {
Console.WriteLine("DerivedClassSpecialFunction2"); }
}

class Function1ImplementationA : DerivedClassSpecialFunction1
{
public override void CallSpecialFunction() {
Console.WriteLine("Function1ImplementationA"); }
}

class Function1ImplementationB : DerivedClassSpecialFunction1
{
public override void CallSpecialFunction() {
Console.WriteLine("Function1ImplementationB"); }
}

class Test
{
static List<BaseClass> mylist = new List<BaseClass>();

public static IEnumerable<DerivedClassSpecialFunction1>
GetSpecialFunction1ClassesOnly()
{
foreach (BaseClass item in mylist)
{
DerivedClassSpecialFunction1 dcsf1 = item as
DerivedClassSpecialFunction1;
if (dcsf1 != null) yield return dcsf1;
}
}

static void Main()
{

mylist.Add(new DerivedClassSpecialFunction1());
mylist.Add(new DerivedClassSpecialFunction2());
mylist.Add(new Function1ImplementationA());
mylist.Add(new Function1ImplementationB());

foreach (DerivedClassSpecialFunction1 item in
GetSpecialFunction1ClassesOnly())
{
item.CallSpecialFunction();
}

}
}


Mattias
 
J

Joanna Carter [TeamB]

"Mike" <[email protected]> a écrit dans le message de (e-mail address removed)...

| So, later if I use this enumerator in a foreach call like this:
|
| foreach (DerivedClassSpecialFunction1 item in
| GetSpecialFunctionClassesOnly())
| {
| item.CallSpecialFunction();
| }
|
| This does not work correctly. Instead of calling the
| Function1ImplementationA version of CallSpecialFunction(), it always
| uses the DerivedClassSpecialFunction version.

I used the following code :

public abstract class BaseClass
{
}

public class DerivedClassSpecialFunction1 : BaseClass
{
public virtual void CallSpecialFunction()
{
}
}

public class DerivedClassSpecialFunction2 : BaseClass
{
}

public class Function1ImplementationA : DerivedClassSpecialFunction1
{
public override void CallSpecialFunction()
{
}
}

public class Function1ImplementationB : DerivedClassSpecialFunction1
{
public override void CallSpecialFunction()
{
}
}

private List<BaseClass> mylist = new List<BaseClass>();

public IEnumerator<DerivedClassSpecialFunction1>
GetSpecialFunction1ClassesOnly()
{
foreach (BaseClass item in mylist)
{
if (item is DerivedClassSpecialFunction1)
yield return (DerivedClassSpecialFunction1) item;
}
}


Then I use dthe following test code :

private void button1_Click(object sender, EventArgs args)
{
mylist.Add(new Function1ImplementationA());
mylist.Add(new DerivedClassSpecialFunction2());
mylist.Add(new Function1ImplementationB());
mylist.Add(new Function1ImplementationA());

IEnumerator<DerivedClassSpecialFunction1> iter =
GetSpecialFunction1ClassesOnly();

while (iter.MoveNext())
iter.Current.CallSpecialFunction();

This then works perfectly calling the correct overriden method only on those
items that are derived from DerivedClassSpecialFunction1.

If I change the test code to the following :

foreach (DerivedClassSpecialFunction1 item in
GetSpecialFunction1ClassesOnly())
{
item.CallSpecialFunction();
}

.... then this doesn't even compile ! You can't use foreach on an
IEnumerator, only on an IEnumerable or an object that has a GetEnumerator()
method.

Joanna
 
J

Joanna Carter [TeamB]

"Joanna Carter [TeamB]" <[email protected]> a écrit dans le message de
Okg%[email protected]...

| If I change the test code to the following :
|
| foreach (DerivedClassSpecialFunction1 item in
| GetSpecialFunction1ClassesOnly())
| {
| item.CallSpecialFunction();
| }
|
| ... then this doesn't even compile ! You can't use foreach on an
| IEnumerator, only on an IEnumerable or an object that has a
GetEnumerator()
| method.

My bad, I forgot to declare the GetSpecialFinction1ClassesOnly method as
static.

Like Mattias, Now I find this code works perfectly as expected.

Did you declare your CallSpecialFunction() as virtual and override where
necessary ??

Joanna
 
G

gummycat

Thanks Mattias and Joanna,

I hate to say it, but turns out the problem was hidden elsewhere and
this so-called "loss of polymorphism" was the false symptom. I did not
trace through the code properly and mis-diagnosed the problem.

Turns out my IEnumerable code was all in perfect working order. This
is a relief as I had fooled myself into thinking a core OO concept had
been trashed by M$... but alas, it is just my ego that is trashed! ;-)

The system I am working on is complex (aren't they all, right?). There
is a method that looks for a context object that is transitory. If it
finds a current context, it will return an IEnumerable from this
context, otherwise it will build it's own empty one. Hard to explain
all the details on why, but the context was being queried at a time
when it could not have been set. This was my mistake. I assumed it
would be there at a time that it could not be. As a result, downstream
in the code, the symptom appeared to be a loss of polymorphism. Once I
traced through the code patiently and properly, it was plain as day for
me.

Thanks so much for taking the time to respond to my query. It was your
quick responses that got me to stop thinking it was a polymorphism
issue and to start looking for the real problem!

What a great community!

Thanks!

Mike
 

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