cannot convert

P

Peter K

Hi,

I have a method in a class:

public void AddUserList(List<IUser> users)
{
...
}

which adds a list of users to the class.

I also have a user class:

public class User : IUser
{
...
}

Why is it I cannot perform a call like this:

List<User> users = new List<User>();
AddUserList(users);


I would have naively thought that as User implements IUser, I could pass a
list of User objects to a method which expects a list of IUser objects (as
a User is an IUser).


Thanks,
Peter
 
J

Jon Skeet [C# MVP]

Why is it I cannot perform a call like this:

List<User> users = new List<User>();
AddUserList(users);

I would have naively thought that as User implements IUser, I could pass a
list of User objects to a method which expects a list of IUser objects (as
a User is an IUser).

Nope. Suppose the AddUserList implementation was this:

users.Add (new OtherIUserImplementation());

At that point your List<User> would contain a reference to something
which isn't a User.

Basically, generics (at least as exposed in C#) don't support
covariance/contravariance. This gives more compile-time safety at the
cost of some convenience.

See http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx for
more information.

Jon
 
P

Peter K

Nope. Suppose the AddUserList implementation was this:

users.Add (new OtherIUserImplementation());

At that point your List<User> would contain a reference to something
which isn't a User.

I'm not following you here... If I have a list defined
List<User> users
then I obviously can't add an OtherUser object, because the list is only
for User objects.

But If I had this list:
List<IUser> users

I would have thought I could add a User:IUser and an OtherUser:IUser, as
the list is defined as accepting IUser objects, and both my objects are
IUser objects.


But my question was about supplying the list to a method, not about
adding objects to the list (maybe it's the same question?).



Basically, generics (at least as exposed in C#) don't support
covariance/contravariance. This gives more compile-time safety at the
cost of some convenience.

See http://blogs.msdn.com/rmbyers/archive/2005/02/16/375079.aspx for
more information.

I'll have a look.

Thanks,
Peter
 
A

Arto V Viitanen

Peter said:
Hi,

I have a method in a class:

public void AddUserList(List<IUser> users)
{
...
}

which adds a list of users to the class.

I also have a user class:

public class User : IUser
{
...
}

Why is it I cannot perform a call like this:

List<User> users = new List<User>();
AddUserList(users);


I would have naively thought that as User implements IUser, I could pass a
list of User objects to a method which expects a list of IUser objects (as
a User is an IUser).

Yep, that is a naive thought. If the method want List<IUser>, you have
to give List<IUser>. So, either make

public void AddUserList(List<User> users)
...
List<User>users = new List<User>()

or

public void AddUserList(List<IUser> users)
...

List<IUser>users = new List<IUser>()

(Actually, I'd use IList, but that is another story).
 
J

Jon Skeet [C# MVP]

I'm not following you here... If I have a list defined
List<User> users
then I obviously can't add an OtherUser object, because the list is only
for User objects.

Indeed - but AddUserList doesn't know it's a List<User>. It only knows
that it has a List<IUser>, which is the point. There's nothing (at
compile time) to stop AddUserList being implemented with the line I
showed.

But my question was about supplying the list to a method, not about
adding objects to the list (maybe it's the same question?).

Indeed it is - you've got to think about what AddUserList *might*
(legally) do given its signature - that explains why you can't pass in
something that would break if it did that.

Jon
 

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