473,383 Members | 1,725 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Generics, IEnumerable and Polymorphism

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

Dec 20 '05 #1
4 2029
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

--
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Dec 20 '05 #2
"Mike" <mi*********@mbna.com> a écrit dans le message de news:
11*********************@g14g2000cwa.googlegroups.c om...

| 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

--
Joanna Carter [TeamB]
Consultant Software Engineer
Dec 20 '05 #3
"Joanna Carter [TeamB]" <jo****@not.for.spam> a écrit dans le message de
news: Ok****************@TK2MSFTNGP09.phx.gbl...

| 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

--
Joanna Carter [TeamB]
Consultant Software Engineer
Dec 20 '05 #4
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

Dec 21 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Kamen Yotov | last post by:
Hello, I got my hands on the PDC preview version of whidbey and I think I managed to break the compiler/runtime with my first Generics/Iterators attempt. The reason I am posting it here is that I...
13
by: Sherif ElMetainy | last post by:
Hello I was just got VS 2005 preview, and was trying generics. I tried the following code int intArray = new int; IList<int> intList = (IList<int>) intArray; it didn't compile, also the...
2
by: Marc | last post by:
Given a class 'Invoice' with a property 'public IMyColl<IInvoiceLine> InvoiceLines' where 'IMyColl<T> : IList<T>' i would like to detect by reflection that 'InvoiceLines' is a...
2
by: rajivpopat | last post by:
I've been reading a discussion thread at http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_frm/thread/119f8362a9f5ff52 regarding typecasting generic collections to...
19
by: Fernando Cacciola | last post by:
I'm puzzled, Why and how _exactly_ is this: void Foo<T>(T v ) where T : Interface/Value/Class/class any better than this void Foo( Interface/Value/Class/object v )
3
by: Wiktor Zychla [C# MVP] | last post by:
since generics allow us to implement several IEnumerable<T> interfaces on a single class, I think that "foreach" should somehow reflect that. suppose we have a enumerable class class C :...
6
by: Mark Rae | last post by:
Hi, I'm in the process of updating an ASP.NET v1.1 web app to v2. The app uses ActiveDirectory a great deal, and I'm trying to use the new System.Collections.Generic namespace where possible,...
10
by: =?Utf-8?B?S29ucmFkIFJ1ZG9scGg=?= | last post by:
Hello, I was wondering if C# 3.0 finally supported generic upcasting. Consider the following code which does work in C# 2: string xs = {"this", "is", "a", "test"}; object ys = xs; Now,...
4
by: CSharper | last post by:
I have a sample as shown in the bottom on the mail. I am trying to see without changing anything in the way the As and Bs handled. I want to make it DRY using generics. I am really interested in...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.