By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,833 Members | 2,067 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,833 IT Pros & Developers. It's quick & easy.

generic interface conversion question

P: n/a
Hi all,

I'm having trouble with a project that I've distilled down to the following
code. Unfortunately it won't compile and gives the following

error (caused by the call to GetHorses() in HorseFarm's GetAnimals() method):
Cannot implicitly convert type 'MyCollection<Horse>' to
'MyCollection<IAnimal>'
I tried creating an implicit conversion operator in the Horse class but the
compiler informed me that it was illegal to do so when the conversion was to
or from an interface.
I can't quite see why the the conversion doesn't occur automatically as the
Horse class implements IAnimal so you'd think a collection of

horses would be a collection of animals (I can after all return a single
Horse whenever an IAnimal is expected).

That being said, my real implementation is much more complex and I really
need to leverage the equivalent of a GetHorses() method within a HorseFarm's
GetAnimals() method.

Is there some type of design pattern for generics that can solve this?

Thanks,

Dave
--------- CODE START ---------------

public class MyCollection<T>
{
}

public interface IAnimal
{
}

public interface IFarm
{
MyCollection<IAnimalGetAnimals();
}

public class Horse : IAnimal
{
}

public class HorseFarm : IFarm
{
MyCollection<Horsehorses = new MyCollection<Horse>();

public MyCollection<HorseGetHorses()
{
return horses;
}

public MyCollection<IAnimalGetAnimals()
{
return GetHorses();
}
}

--------- CODE END ---------------

Nov 14 '07 #1
Share this Question
Share on Google+
13 Replies


P: n/a
Dave Weeden wrote:
Hi all,

I'm having trouble with a project that I've distilled down to the following
code. Unfortunately it won't compile and gives the following

error (caused by the call to GetHorses() in HorseFarm's GetAnimals() method):
Cannot implicitly convert type 'MyCollection<Horse>' to
'MyCollection<IAnimal>'

<...>
Google c# covariance.
..Net (c#?) does not* support covariance and contravariance.

You should be able to define it as IAnimal[] GetAnimals() and call
ToArray() on MyCollection (presuming you're inheriting List<T>).

JB
*Except in some cases. Delegate return types, Array conversion...
Nov 14 '07 #2

P: n/a
I can't quite see why the the conversion doesn't occur automatically as
the
Horse class implements IAnimal so you'd think a collection of

horses would be a collection of animals (I can after all return a single
Horse whenever an IAnimal is expected).
No, because if it was a collection of animals you could add a pig...
Nov 14 '07 #3

P: n/a
Thank John, I am now digging through the following:

http://blogs.msdn.com/ericlippert/ar...e/default.aspx

"John B" wrote:
Dave Weeden wrote:
Hi all,

I'm having trouble with a project that I've distilled down to the following
code. Unfortunately it won't compile and gives the following

error (caused by the call to GetHorses() in HorseFarm's GetAnimals() method):
Cannot implicitly convert type 'MyCollection<Horse>' to
'MyCollection<IAnimal>'
<...>
Google c# covariance.
..Net (c#?) does not* support covariance and contravariance.

You should be able to define it as IAnimal[] GetAnimals() and call
ToArray() on MyCollection (presuming you're inheriting List<T>).

JB
*Except in some cases. Delegate return types, Array conversion...
Nov 14 '07 #4

P: n/a
Hi Ben,

I understand that a collection of animals might contain pigs and other
animals but a collection of horses is definitely comprised solely of horses;
it therefore seems strange that a horse collection can not be used where an
animal collection is expected.

I've adapted my sample code a little (see below) to more closely model what
I'm trying to achieve with my collection that's based on WPF's
ObservableCollection<(namely a way to reference the object which "contains"
the collection so I can navigate my way back up the logical object hierarchy
without tightly coupling myself to the presentation layer).

Also in the sample is how what I'm trying to does work with plain old arrays
but breaks as soon as generics are introduced.

Dave

using System.Collections.ObjectModel;

public class MyCollection<TContainer, TMember: ObservableCollection<TMember>
{
public MyCollection(TContainer container)
{
Container = container;
}

TContainer Container { get; set; } // C# 3.0 automatic property
}

public interface IAnimal
{
}

public interface IFarm
{
IAnimal[] GetAnimalAray();
MyCollection<IFarm, IAnimalGetAnimalCollection();
}

public class Horse : IAnimal
{
}

public class HorseFarm : IFarm
{
IAnimal[] horseArray;
MyCollection<IFarm, HorsehorseCollection;

public HorseFarm()
{
horseArray = new IAnimal[] { };
horseCollection = new MyCollection<IFarm, Horse>(this);
}

public IAnimal[] GetAnimalAray()
{
return horseArray;
}

public MyCollection<IFarm, IAnimalGetAnimalCollection()
{
return horseCollection; // causes compilation error
}
}
"Ben Voigt [C++ MVP]" wrote:
I can't quite see why the the conversion doesn't occur automatically as
the
Horse class implements IAnimal so you'd think a collection of

horses would be a collection of animals (I can after all return a single
Horse whenever an IAnimal is expected).

No, because if it was a collection of animals you could add a pig...
Nov 14 '07 #5

P: n/a
Dave Weeden <dw*****@newsgroup.nospamwrote:
I understand that a collection of animals might contain pigs and other
animals but a collection of horses is definitely comprised solely of horses;
it therefore seems strange that a horse collection can not be used where an
animal collection is expected.
You should really read Eric Lippert's series of posts on variance:

http://blogs.msdn.com/ericlippert/ar...+and+Contravar
iance/default.aspx

Also Rick Byers:

http://blogs.msdn.com/rmbyers/archiv...16/375079.aspx

Consider what you can do with a collection of animals: you can *add*
any animal to it. What would you expect to happen when you add a tiger
to your collection of horses? What about the other pieces of code which
still had a reference to it as a collection of horses?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 14 '07 #6

P: n/a
Thanks, that's definite food for thought and is very likely the root of why
my model isn't quite right.

IIRC, the array returned by GetAnimalArray() is a copy so the replacing one
of the horse elements in that copy with a tiger would not cause a problem.

John B's post from above had also pointed me down the road towards Eric's
posts.

I'll definitely be checking them out :)

Thanks!

"Jon Skeet [C# MVP]" wrote:
Dave Weeden <dw*****@newsgroup.nospamwrote:
I understand that a collection of animals might contain pigs and other
animals but a collection of horses is definitely comprised solely of horses;
it therefore seems strange that a horse collection can not be used where an
animal collection is expected.

You should really read Eric Lippert's series of posts on variance:

http://blogs.msdn.com/ericlippert/ar...+and+Contravar
iance/default.aspx

Also Rick Byers:

http://blogs.msdn.com/rmbyers/archiv...16/375079.aspx

Consider what you can do with a collection of animals: you can *add*
any animal to it. What would you expect to happen when you add a tiger
to your collection of horses? What about the other pieces of code which
still had a reference to it as a collection of horses?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 14 '07 #7

P: n/a
Jon Skeet [C# MVP] wrote:
<....>
Consider what you can do with a collection of animals: you can *add*
any animal to it. What would you expect to happen when you add a tiger
to your collection of horses?
string[] strings = new string[] { "a", "b", "c", "d", "e", "f", "g" };
object[] objs = (object[])strings;
objs[0] = new object(); //oops

Ideally, not what happens when you do the above :)

<...>

JB
Nov 15 '07 #8

P: n/a
John B <jb******@yahoo.comwrote:
Jon Skeet [C# MVP] wrote:
<....>
Consider what you can do with a collection of animals: you can *add*
any animal to it. What would you expect to happen when you add a tiger
to your collection of horses?

string[] strings = new string[] { "a", "b", "c", "d", "e", "f", "g" };
object[] objs = (object[])strings;
objs[0] = new object(); //oops

Ideally, not what happens when you do the above :)
Exactly. Generics is meant to give compile-time type safety. Array
variance punts the type safety to execution time :(

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 15 '07 #9

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:MP*********************@msnews.microsoft.com. ..
John B <jb******@yahoo.comwrote:
>Jon Skeet [C# MVP] wrote:
<....>
Consider what you can do with a collection of animals: you can *add*
any animal to it. What would you expect to happen when you add a tiger
to your collection of horses?

string[] strings = new string[] { "a", "b", "c", "d", "e", "f", "g" };
object[] objs = (object[])strings;
objs[0] = new object(); //oops

Ideally, not what happens when you do the above :)

Exactly. Generics is meant to give compile-time type safety. Array
variance punts the type safety to execution time :(
I think array variance ought to require the /unsafe compiler switch.
>
--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

Nov 15 '07 #10

P: n/a
On Nov 15, 3:48 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
Exactly. Generics is meant to give compile-time type safety. Array
variance punts the type safety to execution time :(

I think array variance ought to require the /unsafe compiler switch.
Hmm... it's a slightly different type of safety, I think - a separate
switch, perhaps. Or perhaps it should just have been disallowed in the
first place. Apparently it was included mostly to be compatible with
Java, bizarrely enough.

Jon
Nov 15 '07 #11

P: n/a

"Jon Skeet [C# MVP]" <sk***@pobox.comwrote in message
news:92**********************************@e1g2000h sh.googlegroups.com...
On Nov 15, 3:48 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospamwrote:
Exactly. Generics is meant to give compile-time type safety. Array
variance punts the type safety to execution time :(

I think array variance ought to require the /unsafe compiler switch.

Hmm... it's a slightly different type of safety, I think - a separate
switch, perhaps. Or perhaps it should just have been disallowed in the
first place. Apparently it was included mostly to be compatible with
Java, bizarrely enough.

Jon
No, there's advantages of overloading the "/unsafe" switch such as running
afoul of all the code style guides out there that say "no /unsafe". Because
the people who can't get unsafe code right are not going to get array
variance right either.

Yes, I realize that array variance is permissible in a partial-trust
environment, because of the extra runtime type-checking inserted by the
compiler.

I guess we could use the "/theoreticallyincorrect" switch instead?
Nov 15 '07 #12

P: n/a
Thanks all of you guys for pointing me down the right road, I get it now.

It's nice to dive back into theory sometimes :)

"Dave Weeden" wrote:
Thanks, that's definite food for thought and is very likely the root of why
my model isn't quite right.

IIRC, the array returned by GetAnimalArray() is a copy so the replacing one
of the horse elements in that copy with a tiger would not cause a problem.

John B's post from above had also pointed me down the road towards Eric's
posts.

I'll definitely be checking them out :)

Thanks!

"Jon Skeet [C# MVP]" wrote:
Dave Weeden <dw*****@newsgroup.nospamwrote:
I understand that a collection of animals might contain pigs and other
animals but a collection of horses is definitely comprised solely of horses;
it therefore seems strange that a horse collection can not be used where an
animal collection is expected.
You should really read Eric Lippert's series of posts on variance:

http://blogs.msdn.com/ericlippert/ar...+and+Contravar
iance/default.aspx

Also Rick Byers:

http://blogs.msdn.com/rmbyers/archiv...16/375079.aspx

Consider what you can do with a collection of animals: you can *add*
any animal to it. What would you expect to happen when you add a tiger
to your collection of horses? What about the other pieces of code which
still had a reference to it as a collection of horses?

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 15 '07 #13

P: n/a
Ben Voigt [C++ MVP] <rb*@nospam.nospamwrote:
Hmm... it's a slightly different type of safety, I think - a separate
switch, perhaps. Or perhaps it should just have been disallowed in the
first place. Apparently it was included mostly to be compatible with
Java, bizarrely enough.

No, there's advantages of overloading the "/unsafe" switch such as running
afoul of all the code style guides out there that say "no /unsafe". Because
the people who can't get unsafe code right are not going to get array
variance right either.
Ooh, I don't know about that. I personally steer well clear of unsafe
code, and don't want to think about pinning etc - but I'm comfortable
enough getting variance right.
Yes, I realize that array variance is permissible in a partial-trust
environment, because of the extra runtime type-checking inserted by the
compiler.
Do you mean the JIT compiler? It's not done by the C# compiler.
I guess we could use the "/theoreticallyincorrect" switch instead?
Well, I'd go for something like: /arrayvariance={warn,error,allow} - or
just make it a warning that can be controlled in the same way as other
warnings.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 15 '07 #14

This discussion thread is closed

Replies have been disabled for this discussion.