简体   繁体   中英

Why can I not infer an interface from a constrained generic collection?

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.

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> .

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.

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM