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

Extending objects that get returned as generics

P: n/a
I ran into a unique situation today whereby I have a core library that
uses generics to return users from Active Directory. Example:

List<ADUser> users = ADUser.GetByName("First", "Last");

This works great. However, what I need to do is extend the ADUser
object like so:

class DataGridUser : ADUser
{
// add some new properties
// add some new methods for databinding
}

I can't figure out how to extend it though since the GetByName() returns
a List<ADUser>. Trying this doesn't work:

List<DataGridUser> users = DataGridUser.GetByName("First", "Last");

This throws an exception that GetByName cannot convert DataGridUser to
ADUser. What am I missing or doing wrong? Anyone got any ideas?

-Keith
Jan 16 '06 #1
Share this Question
Share on Google+
20 Replies


P: n/a
Keith Elder wrote:
I ran into a unique situation today whereby I have a core library that
uses generics to return users from Active Directory. Example:

List<ADUser> users = ADUser.GetByName("First", "Last");

This works great. However, what I need to do is extend the ADUser
object like so:

class DataGridUser : ADUser
{
// add some new properties
// add some new methods for databinding
}

I can't figure out how to extend it though since the GetByName() returns
a List<ADUser>. Trying this doesn't work:

List<DataGridUser> users = DataGridUser.GetByName("First", "Last");

This throws an exception that GetByName cannot convert DataGridUser to
ADUser. What am I missing or doing wrong? Anyone got any ideas?


Are you sure the compiler doesn't complain that it can't convert
List<ADUser> to List<DataGridUser>? The problem is that List<ADUser>
and List<DataGridUser> are entirely different types, even though
DataGridUser derives from ADUser.

There's a recent thread on this newsgroup about it, called "Casting
generic collections & inheritance". Look on groups.google.com for it if
you don't have it locally.

If this isn't what you mean, please provide a short but complete
example which demonstrates your problem. See
http://www.pobox.com/~skeet/csharp/complete.html for more details on
what I mean by that.

Jon

Jan 16 '06 #2

P: n/a
"Keith Elder" <ke***@removethis.dotnetpimps.net> a écrit dans le message de
news: eY********************@comcast.com...

| I can't figure out how to extend it though since the GetByName() returns
| a List<ADUser>. Trying this doesn't work:
|
| List<DataGridUser> users = DataGridUser.GetByName("First", "Last");
|
| This throws an exception that GetByName cannot convert DataGridUser to
| ADUser. What am I missing or doing wrong? Anyone got any ideas?

Correct. See Jon's reply. But assuming that you are creating DataGridUser
instances and adding them to a List<ADUser>, then you can always cast the
individual items to DataGridUser.

As Jon said, the two type of generic list are not related, they are sibling
classes. Your other choice is to modify the GetByName method or add another
method that returns the type of list that you are wanting.

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Jan 16 '06 #3

P: n/a
Joanna Carter [TeamB] wrote:
"Keith Elder" <ke***@removethis.dotnetpimps.net> a écrit dans le message de
news: eY********************@comcast.com...

| I can't figure out how to extend it though since the GetByName() returns
| a List<ADUser>. Trying this doesn't work:
|
| List<DataGridUser> users = DataGridUser.GetByName("First", "Last");
|
| This throws an exception that GetByName cannot convert DataGridUser to
| ADUser. What am I missing or doing wrong? Anyone got any ideas?

Correct. See Jon's reply. But assuming that you are creating DataGridUser
instances and adding them to a List<ADUser>, then you can always cast the
individual items to DataGridUser.

As Jon said, the two type of generic list are not related, they are sibling
classes. Your other choice is to modify the GetByName method or add another
method that returns the type of list that you are wanting.

Joanna

Thanks Joanna,

I think my problem lies in the fact that I really cannot touch this core
library ADUser. Extending it is the only way to really modify it.
Think of it no differently than System.Data.XXXX. Pretty much all apps
rely on that object to work and it rarely gets modified.

I did try casting to DataGridUser, however it fails because the method
GetByName returns List<ADUser>. Care to give an example of what you
were thinking?
Jan 16 '06 #4

P: n/a
"Keith Elder" <ke***@removethis.dotnetpimps.net> a écrit dans le message de
news: X8******************************@comcast.com...

| I did try casting to DataGridUser, however it fails because the method
| GetByName returns List<ADUser>. Care to give an example of what you
| were thinking?

{
List<ADUser> users = DataGridUser.GetByName("First", "Last");

if (users.Count > 0)
DataGridUser user = (DataGridUser) users[0];
...
}

This assumes that the objects in the list really are DataGridUsers.

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Jan 16 '06 #5

P: n/a
Keith Elder <ke***@removethis.dotnetpimps.net> wrote in
news:eY********************@comcast.com:
This throws an exception that GetByName cannot convert DataGridUser to
ADUser. What am I missing or doing wrong? Anyone got any ideas?


I have two things to say about this...

First, being one of the people involved in the thread that Jon referred to,
I would think that the problem here is that the person that wrote the
ADUser library didn't fully consider what users might want to do with those
objects and functions that the library provides. What I mean by this is
that there are probably functions provided by the library that you want to
use List<DataGridUser> with but can't because they expect List<ADUser>, for
example:

public void DoSomething(List<ADUser> list) { ... }

Based on the discussion thread with Jon, what the author should have done
is:

public void DoSomething<T>(List<T> list) where T : ADUser { ... }

It wouldn't surprise me at all if a lot of libraries that are written to
support generics aren't written this way, simply because they don't have to
be.

Jon, would you agree that *in general*, any functions which accept generics
should be written to support this least generic form of the function? It
almost seems as if the first form (with List<ADUser>) of the function
signature should be the "not recommended" way of writing this function,
because it totally limits the flexibility of the function as it relates to
classes derived from ADUser.

Second, Keith, if you can't make alterations to the base library, then you
might want to look at the "Decorator" pattern. I think it might help here.
Here's one:

http://www.dofactory.com/Patterns/PatternDecorator.aspx

-mdb
Jan 16 '06 #6

P: n/a
Michael Bray wrote:
Keith Elder <ke***@removethis.dotnetpimps.net> wrote in
news:eY********************@comcast.com:
This throws an exception that GetByName cannot convert DataGridUser to
ADUser. What am I missing or doing wrong? Anyone got any ideas?


I have two things to say about this...

First, being one of the people involved in the thread that Jon referred to,
I would think that the problem here is that the person that wrote the
ADUser library didn't fully consider what users might want to do with those
objects and functions that the library provides. What I mean by this is
that there are probably functions provided by the library that you want to
use List<DataGridUser> with but can't because they expect List<ADUser>, for
example:

public void DoSomething(List<ADUser> list) { ... }

Based on the discussion thread with Jon, what the author should have done
is:

public void DoSomething<T>(List<T> list) where T : ADUser { ... }

It wouldn't surprise me at all if a lot of libraries that are written to
support generics aren't written this way, simply because they don't have to
be.

Jon, would you agree that *in general*, any functions which accept generics
should be written to support this least generic form of the function? It
almost seems as if the first form (with List<ADUser>) of the function
signature should be the "not recommended" way of writing this function,
because it totally limits the flexibility of the function as it relates to
classes derived from ADUser.

Second, Keith, if you can't make alterations to the base library, then you
might want to look at the "Decorator" pattern. I think it might help here.
Here's one:

http://www.dofactory.com/Patterns/PatternDecorator.aspx

-mdb

Mark, I think you are absolutely right, the way it is written locks it
in. Here is how the library is written sort of sudo code:

class ADUser
{
public string FirstName;
public string LastName;
public string PictureURL;

public static List<ADUser> GetUsersByName(string firstName,string lastName)
{
// pretend this searched Active directory
// and found two users with the name frank
List<ADUser> users = new List<ADUser>();
users.Add(new ADUser("frank", "wannabe"));
users.Add(new ADUser("frank", "cats"));
return users;
}
}

Based on that, what do you think *should* be done on this?
Jan 16 '06 #7

P: n/a
Keith Elder <ke***@removethis.dotnetpimps.net> wrote in
news:Ua******************************@comcast.com:
Based on that, what do you think *should* be done on this?


On that, nothing.

In my first response, I was assuming that the problem was that the library
also provides functions that take a List<ADUser>, and that you cannot use
these functions because you want to derive DataGridUser from ADUser, and
then pass List<DataGridUser> to that function (which doesn't compile.)
This may have been assuming too much.

It seems that you simply want to convert the List<ADUser> to your derived
List<DataGridUser>. If that's the case, then you can use something like
this:

public new List<DataGridUser> GetByName(...)
{
List<ADUser> adUsers = base.GetByName(...)
List<DataGridUser> dgUsers = new List<DataGridUser>(adUsers.ToArray());
return dgUsers;
}

-mdb
Jan 16 '06 #8

P: n/a
Michael Bray wrote:
Keith Elder <ke***@removethis.dotnetpimps.net> wrote in
news:Ua******************************@comcast.com:
Based on that, what do you think *should* be done on this?


On that, nothing.

In my first response, I was assuming that the problem was that the library
also provides functions that take a List<ADUser>, and that you cannot use
these functions because you want to derive DataGridUser from ADUser, and
then pass List<DataGridUser> to that function (which doesn't compile.)
This may have been assuming too much.

It seems that you simply want to convert the List<ADUser> to your derived
List<DataGridUser>. If that's the case, then you can use something like
this:

public new List<DataGridUser> GetByName(...)
{
List<ADUser> adUsers = base.GetByName(...)
List<DataGridUser> dgUsers = new List<DataGridUser>(adUsers.ToArray());
return dgUsers;
}

-mdb


Actually to make you feel better, there are some functions which take
the list List<ADUser> and then do things with that list in the ADUser
object. Those methods need to be re-structured as well it seems.

Thanks Mark, a great help.

-Keith
Jan 16 '06 #9

P: n/a
class DataGridUser : ADUser
{

public DataGridUser(ADuser aduser)
{
// presumably you have this ctor.
}

public static List<DataGridUser> GetUsersByName(string firstName,string
lastName)
{
List<ADUser> users = ADUser.GetUsersByName(firstName,lastName);
List<DataGridUser> dgusers = new List<DataGridUser> (users.Size);
foreach(ADUser user in users)
{
dgusers.Add(new DataGridUser(user));
}

return dgusers;
}

Of course, this will have the same expansion problems as the original. TO
make use of Michael's suggestion:

static public void GetUsersByName<T>(List<T> list, string firstName,string
lastName) where T : DataGridUser
{

List<ADUser> users = ADUser.GetUsersByName(firstName,lastName);
foreach(ADUser user in users)
{
list.Add(new T(user));
}
}

This would be call via:
List<DataGridUser> dgusers = new List<DataGridUser> ();
GetUsersByName(dgusers, "John", "Smith");
Now, I'm a little hazy on allowable C# generics syntax, but In C++
templates, we could write that as

static List<T> GetUsersByName<T>(string firstName,string lastName)
{
}

List<DataGridUser> dgusers = GetUsersByName<DataGridUser>("John",
"Smith");

--
Truth,
James Curran
[erstwhile VC++ MVP]

Home: www.noveltheory.com Work: www.njtheater.com
Blog: www.honestillusion.com Day Job: www.partsearch.com
"Keith Elder" <ke***@removethis.dotnetpimps.net> wrote in message
news:Ua******************************@comcast.com. ..
Mark, I think you are absolutely right, the way it is written locks it
in. Here is how the library is written sort of sudo code:

class ADUser
{
public string FirstName;
public string LastName;
public string PictureURL;

public static List<ADUser> GetUsersByName(string firstName,string lastName) {
// pretend this searched Active directory
// and found two users with the name frank
List<ADUser> users = new List<ADUser>();
users.Add(new ADUser("frank", "wannabe"));
users.Add(new ADUser("frank", "cats"));
return users;
}
}

Based on that, what do you think *should* be done on this?

Jan 16 '06 #10

P: n/a
Keith Elder <ke***@removethis.dotnetpimps.net> wrote:

<snip>
Mark, I think you are absolutely right, the way it is written locks it
in. Here is how the library is written sort of sudo code:

class ADUser
{
public string FirstName;
public string LastName;
public string PictureURL;

public static List<ADUser> GetUsersByName(string firstName,string lastName)
{
// pretend this searched Active directory
// and found two users with the name frank
List<ADUser> users = new List<ADUser>();
users.Add(new ADUser("frank", "wannabe"));
users.Add(new ADUser("frank", "cats"));
return users;
}
}

Based on that, what do you think *should* be done on this?


Well, you haven't shown your DataGridUser class. Does it have a method
GetUsersByName as well?

--
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
Jan 16 '06 #11

P: n/a
Jon Skeet [C# MVP] wrote:
Keith Elder <ke***@removethis.dotnetpimps.net> wrote:

<snip>
Mark, I think you are absolutely right, the way it is written locks it
in. Here is how the library is written sort of sudo code:

class ADUser
{
public string FirstName;
public string LastName;
public string PictureURL;

public static List<ADUser> GetUsersByName(string firstName,string lastName)
{
// pretend this searched Active directory
// and found two users with the name frank
List<ADUser> users = new List<ADUser>();
users.Add(new ADUser("frank", "wannabe"));
users.Add(new ADUser("frank", "cats"));
return users;
}
}

Based on that, what do you think *should* be done on this?


Well, you haven't shown your DataGridUser class. Does it have a method
GetUsersByName as well?


The DataGridUser class is very simple. To bind to the datagrid, we need
to convert the photo url in ADUser to a Bitmap. So, no, there isn't a
GetUsersByName in DataGridUser.

class DataGridUser : ADUser
{
private Bitmap photo;
public Bitmap Photo
{
get
{
return Some.Common.Lib.GetImageFromURL(this.PhotoURL);
}
}
}
Jan 16 '06 #12

P: n/a
"James Curran" <ja*********@mvps.org> wrote in
news:Oo**************@TK2MSFTNGP10.phx.gbl:
Of course, this will have the same expansion problems as the original.
TO make use of Michael's suggestion:

static public void GetUsersByName<T>(List<T> list, string
firstName,string lastName) where T : DataGridUser
{

List<ADUser> users =
ADUser.GetUsersByName(firstName,lastName); foreach(ADUser user
in users) {
list.Add(new T(user));
}
}


A fine example of why this is likely to be a common problem! I forgot to
even think of doing it myself! :)

However I was unable to get this to work in my own example (using
Person/Farmer, pardon the shift).

public class Person { ... }
public class Farmer : Person { ... }

private static void GetNames<T>(List<T> list) where T : Person
{
Person mike = new Person("mike");

// This doesn't compile
list.Add(mike);
}

with the compiler saying that it can't convert 'Person' to 'T'. Am I
missing something??

-mdb
Jan 16 '06 #13

P: n/a
Keith Elder <ke***@removethis.dotnetpimps.net> wrote:
The DataGridUser class is very simple. To bind to the datagrid, we need
to convert the photo url in ADUser to a Bitmap. So, no, there isn't a
GetUsersByName in DataGridUser.

class DataGridUser : ADUser
{
private Bitmap photo;
public Bitmap Photo
{
get
{
return Some.Common.Lib.GetImageFromURL(this.PhotoURL);
}
}
}


In that case, a call to DataGridUser.GetUsersByName actually compiles
to a call to ADUser.GetUsersByName anyway.

It sounds like you'll either need to convert the returned list, or just
treat every user as an ADUser until you really *need* to treat it as a
DataGridUser, at which point you can use "as" or cast.

--
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
Jan 16 '06 #14

P: n/a
Michael Bray <mbray@makeDIntoDot_ctiusaDcom> wrote:
A fine example of why this is likely to be a common problem! I forgot to
even think of doing it myself! :)

However I was unable to get this to work in my own example (using
Person/Farmer, pardon the shift).

public class Person { ... }
public class Farmer : Person { ... }

private static void GetNames<T>(List<T> list) where T : Person
{
Person mike = new Person("mike");

// This doesn't compile
list.Add(mike);
}

with the compiler saying that it can't convert 'Person' to 'T'. Am I
missing something??


Absolutely - if you try to add a Person to a List<Farmer>, that
shouldn't work, should it?

I don't know any way of expressing in C# that T must be a *base* class
of Person, rather than *derived* from Person. I'm pretty sure it's
possible in Java, but I'm bad at remembering the syntax there too...

I'll keep an eye out for it though.

--
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
Jan 16 '06 #15

P: n/a
Jon Skeet [C# MVP] <sk***@pobox.com> wrote in
news:MP************************@msnews.microsoft.c om:
Absolutely - if you try to add a Person to a List<Farmer>, that
shouldn't work, should it?
Yeah I think this is another problem of the "wording" but in this case
its the actual (correct) code that is confusing. It just seems strange
that if I receive a List<T> where T: Person that I can't add a 'Person'
to it. But of course you make perfect sense in your example - if I
receive a List<Farmer> (where Farmer: Person) then of course I can't add
a Person to it because not every person is a farmer! (E I E I O).

I guess when one sees "where T: Person" they can ONLY say "T is a
Person" from OUTSIDE the function. When viewed from INSIDE the
function, T is T, and even though whatever T is may be derived from
Person, you can't treat it as a Person directly.

For example, the following compiles:

static Person mike = new Person("mike");
static Farmer john = new Farmer("john", 10);
static Farmer bob = new Farmer("bob", 20);

private static List<T> GetNames<T>() where T: Person
{
List<T> l = new List<T>();

l.Add(mike as T);
l.Add(john as T);
l.Add(bob as T);

return l;
}

private static void Test()
{
List<Person> people = GetNames<Person>();
List<Farmer> farmers = GetNames<Farmer>();
}

Both 'people' and 'farmers' will have 3 entries, but the first entry in
'farmers' is null (as expected). Furthermore, the entry that is null is
'mike', which IS a person, which is what we are specifying T should be.

Inside the function, you really do have to look at T as a macro
replacement more than simply being a Type specifier. Outside the
function, it is definitely a type specifier.

I don't know any way of expressing in C# that T must be a *base* class
of Person, rather than *derived* from Person. I'm pretty sure it's
possible in Java, but I'm bad at remembering the syntax there too...


I guess in this case making the parameter a List<T> doesn't make
sense... it should simply return List<Person>, or for Keith's example,
it should return a List<ADUser>. But in that case the function isn't
generic, which was the whole point, so it doesn't matter anyway.

My brain hurts now. :)

-mdb

Jan 16 '06 #16

P: n/a
Keith Elder wrote:
I ran into a unique situation today whereby I have a core library that
uses generics to return users from Active Directory. Example:

List<ADUser> users = ADUser.GetByName("First", "Last");

This works great. However, what I need to do is extend the ADUser
object like so:

class DataGridUser : ADUser
{
// add some new properties
// add some new methods for databinding
}

I can't figure out how to extend it though since the GetByName() returns
a List<ADUser>. Trying this doesn't work:

List<DataGridUser> users = DataGridUser.GetByName("First", "Last");

This throws an exception that GetByName cannot convert DataGridUser to
ADUser. What am I missing or doing wrong? Anyone got any ideas?

-Keith


I took another stab at this a different way thinking I could solve the
problem but I seemed to have run into a snafu with null exception and
casting. Here is what I did to the base library class trying to come up
with a more flexible solution. The problem lies within the
GetUsersByName() where user is always null and cannot be converted.
Anyone see something that I'm missing and a way to fix this?
class ADUser
{
public string FirstName;
public string LastName;

public static List<T> GetUsersByName<T>(string firstName, string
lastName) where T : ADUser
{
List<T> users = new List<T>();
using (DirectorySearcher ds = GetDirectorySearcher())
{
ds.SearchRoot = AD.DirectoryEntry;
ds.PageSize = 100;
ds.Filter = field;
try
{
using (SearchResultCollection result = ds.FindAll())
{
foreach (SearchResult singleResult in result)
{
// LINE BELOW IS THE ONE IN QUESTION
// IT ALWAYS RETURNS user as null
T user = new ADUser(singleResult) as T;
users.Add(user);
}
}
return users;
}
catch (Exception ex)
{
throw new Exception("Something blew up");
}
}
}
}

class DataGridUser : ADUser
{
private Bitmap photo = null;
public Bitmap Photo
{
get
{
if (photo == null) { this.photo
Some.Lib.GetImageFromURL(this.PhotoURL); }
return this.photo;
}
}
}
class WinForm
{
WinForm()
{
List<DataGridUser> users =
ADUser.GetUsersByName<DataGridUser>("frank", String.Empty);
}
}
Jan 16 '06 #17

P: n/a
Keith Elder <ke***@removethis.dotnetpimps.net> wrote:
I took another stab at this a different way thinking I could solve the
problem but I seemed to have run into a snafu with null exception and
casting. Here is what I did to the base library class trying to come up
with a more flexible solution. The problem lies within the
GetUsersByName() where user is always null and cannot be converted.
Anyone see something that I'm missing and a way to fix this?


Yes, it will always be null if T isn't ADUser. Imagine if you'd asked
it to treat "new object()" as a string - it couldn't.

Now, the code you've given doesn't create a new DataGridUser, and
doesn't indicate that you'd *need* to. Where would you be setting the
Photo property anyway?

--
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
Jan 16 '06 #18

P: n/a
Jon Skeet [C# MVP] wrote:
Keith Elder <ke***@removethis.dotnetpimps.net> wrote:
I took another stab at this a different way thinking I could solve the
problem but I seemed to have run into a snafu with null exception and
casting. Here is what I did to the base library class trying to come up
with a more flexible solution. The problem lies within the
GetUsersByName() where user is always null and cannot be converted.
Anyone see something that I'm missing and a way to fix this?


Yes, it will always be null if T isn't ADUser. Imagine if you'd asked
it to treat "new object()" as a string - it couldn't.

Now, the code you've given doesn't create a new DataGridUser, and
doesn't indicate that you'd *need* to. Where would you be setting the
Photo property anyway?

My bad, the WinForm class should have been:

class WinForm
{
WinForm()
{
List<DataGridUser> users =
DataGridUser.GetUsersByName<DataGridUser>("frank", String.Empty);
}
}

After reading Michaels last post a ways up in this thread, I see there
really isn't a way to not have user returned as the type specified. We
were pretty much typing the same examples it seems.

Unless someone can talk me out of it, I'm going back to:

public static ArrayList GetUsersByName(string firstName, string lastName)
{
ArrayList ar = new ArrayList();
ar.Add(new ADUser());
ar.Add(new ADuser());
return ar;
}

ArrayList users = ADUser.GetUsersByName("frank", String.Empty);

I think this is really more flexible when trying to do inheritance
unless someone can talk me out of it.
Jan 16 '06 #19

P: n/a
Keith Elder <ke***@removethis.dotnetpimps.net> wrote:
Now, the code you've given doesn't create a new DataGridUser, and
doesn't indicate that you'd *need* to. Where would you be setting the
Photo property anyway?

<snip>
After reading Michaels last post a ways up in this thread, I see there
really isn't a way to not have user returned as the type specified. We
were pretty much typing the same examples it seems.

Unless someone can talk me out of it, I'm going back to:

public static ArrayList GetUsersByName(string firstName, string lastName)
{
ArrayList ar = new ArrayList();
ar.Add(new ADUser());
ar.Add(new ADuser());
return ar;
}

ArrayList users = ADUser.GetUsersByName("frank", String.Empty);

I think this is really more flexible when trying to do inheritance
unless someone can talk me out of it.


What does that buy you? You're still not creating any DataGridUsers in
the list. I don't see any advantage.

If you need to create a list of DataGridUsers, use List<DataGridUser>
at that point, and only at that point. If you're going to create a list
which may have some DataGridUsers and some plain ADUsers in, you might
as well use a List<ADUser> and check each element.

--
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
Jan 17 '06 #20

P: n/a
Michael Bray <mbray@makeDIntoDot_ctiusaDcom> wrote:
Absolutely - if you try to add a Person to a List<Farmer>, that
shouldn't work, should it?
Yeah I think this is another problem of the "wording" but in this case
its the actual (correct) code that is confusing. It just seems strange
that if I receive a List<T> where T: Person that I can't add a 'Person'
to it. But of course you make perfect sense in your example - if I
receive a List<Farmer> (where Farmer: Person) then of course I can't add
a Person to it because not every person is a farmer! (E I E I O).


Exactly.
I guess when one sees "where T: Person" they can ONLY say "T is a
Person" from OUTSIDE the function. When viewed from INSIDE the
function, T is T, and even though whatever T is may be derived from
Person, you can't treat it as a Person directly.
No - in the same way that if you were passed a Farmer[] you couldn't
set an element in that to a new Person. (What I'm saying is that this
isn't a new issue with generics :)

<snip>
Inside the function, you really do have to look at T as a macro
replacement more than simply being a Type specifier. Outside the
function, it is definitely a type specifier.
I'm not entirely sure what you mean - but I suspect everyone thinks of
generics in a very slightly different way anyway.
I don't know any way of expressing in C# that T must be a *base* class
of Person, rather than *derived* from Person. I'm pretty sure it's
possible in Java, but I'm bad at remembering the syntax there too...


I guess in this case making the parameter a List<T> doesn't make
sense...


Well, it does - it's just that you can't express the constraint you
want to be able to.
it should simply return List<Person>, or for Keith's example,
it should return a List<ADUser>. But in that case the function isn't
generic, which was the whole point, so it doesn't matter anyway.


Indeed :)

--
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
Jan 17 '06 #21

This discussion thread is closed

Replies have been disabled for this discussion.