Reputation: 11362
I have a piece of code that works like this:
public IEnumerable<ICacheMember> Flubvert( IEnumerable<ICacheMember> members )
{
// do some stuff to members
return members;
}
However I am confused as to why I can't do this:
public IEnumerable<T> ExecuteFlubversion<T>( IEnumerable<T> memberList ) where T: class,ICacheMember
{
return Flubvert( memberList );
}
Surely the constraint on the generic should guarantee that memberList
is an IEnumerable of the ICacheMember
type? Do I really need to convert a collection of existing ( but implicit ) ICacheMember
objects into explicit ICacheMember
objects and then convert them back afterwards? I can understand that I might need to convert them back given the method signature of Flubvert
but I don't see why I should have to convert them in the method call. This is what I am doing in the working code but it seems completely out of keeping with the generally elegant behaviour of generics so I think I must be misunderstanding something about how this is supposed to operate.
Upvotes: 3
Views: 112
Reputation: 4059
At risk of not directly answering the question, can you change the signature of Flubvert to a generic? If you make Flubvert generic, the rest of the method code will stay the same and you can still assume that the members will be implementers of ICacheMember.
public IEnumerable<T> Flubvert<T>(IEnumerable<T> members)
where T : class, ICacheMember
{
// do some stuff to members
return members;
}
public IEnumerable<T> ExecuteFlubversion<T>(IEnumerable<T> memberList)
where T : class,ICacheMember
{
return Flubvert(memberList);
}
Upvotes: 0
Reputation: 2255
Lets say you have:
interface ICacheMemberSub : ICacheMember
{
...
}
And you call your function like this:
ExecuteFlubversion<ICacheMemberSub>(cacheMember);
This function will try to return an object with type IEnumerable<ICacheMember>
, and that is not necessarily castable to IEnumerable<ICacheMemberSub>
, hence the error.
Upvotes: 0
Reputation: 61952
First of all covariance of IEnumerable<out T>
(and other generic types) only works when T
is a reference type, so you need:
public IEnumerable<ICacheMember> ExecuteFlubversion<T>(IEnumerable<T> memberList)
where T: class, ICacheMember // NOTE 'class'
{
var flub = Flubvert(memberList); // can you call with 'memberList'?
return flub; // can you return that type?
// depending on what 'Flubvert' does, maybe return 'IEnumerable<T>'
// and say:
// return (IEnumerable<T>)flub;
}
Also note that I changed the return value. The C# compiler cannot guarantee that the returned object from the non-generic Flubvert
method is anything more specific than IEnumerable<ICacheMember>
.
Upvotes: 4