2

I'm in a dilemma to choose the return type of collections when writing generic extension methods for an API. I have read discussions on SO on what collection type to return and what should be the design choices. I generally prefer to accept the most basic type as argument and return the richest type.

I'm now thinking of returning the same type that is provided with. Irrespective of whether this is a good choice or not, is there a way this can be accomplished in an easy to use manner?

For eg. lets I have this:

 public static IEnumerable<T> Generize<T>(this IEnumerable<T> source)
                                         where T : new()
 {
     var lst = source.ToList();
     lst.Add(new T());
     return lst.AsEnumerable(); //since return type is IEnumerable.
 }

Now I want to return an IEnumerable, ICollection or IList depending on the argument source. So I modified this a bit.

 public static S Generize<S, T>(this S source) where S : IEnumerable<T>
                                               where T : new()
 {
     var lst = source.ToList();
     lst.Add(new T());
     return (S)lst.AsEnumerable(); //not sure if this works
 }

The main problem I'm facing is I can't get to call the function Generize.

var d = new List<int> { 23, 23 };

d.Generize(); //can not find definition and no extension method by the name.....

d.Generize<List<int>, int>(); //works but so ugly..
  1. As Marc points out the casting doesn't work everywhere. Is there a better way to return a collection of type S from a List<T> if S is anyway a IEnumerable<T> ?

  2. Can it be done without specifying types such that types are inferred automatically?

  3. Also why is d.Generize() giving definition not found error rather than types cannot be inferred error?

Edit:

Though IEnumberable<T> can be of any concrete type, in my case it would have been only the normally found ones like T[] or List<T> or few more from Linq namsespace. Handling them all wont be easy. Just pointing out that the original question doesn't make sense to me now. Thanks all..!

4

1 回答 1

0

警告:好吧,我的问题不是很好,我的想法有点愚蠢。这只是为了回答我的帖子,我不推荐它。我将依靠返回正确List<T>的生产代码。

一种方法是处理一些已知类型的集合类

public static S Generize<S, T>(this S source, T dummyVariable) 
                              where S : class, IEnumerable<T>
{
    var lst = source.ToList();
    lst.Add(dummyVariable);

    if (source is T[])
        return lst.ToArray() as S;

    if (source is List<T>)
        return lst as S;

    if (source is Collection<T>)
        return new Collection<T>(lst) as S;

    throw new TypeAccessException();
}

更笼统地说,我将使用一些反射..

public static S Generize<S, T>(this S source, T dummyVariable) 
                              where S : class, IEnumerable<T>
{
    var lst = source.ToList();
    lst.Add(dummyVariable);

    if (source is Array)
        return lst.ToArray() as S;

    foreach (var c in typeof(S).GetConstructors())
    {
        var p = c.GetParameters();

        if (p.Length != 1)
            continue;

        if (typeof(IEnumerable<T>).IsAssignableFrom(p[0].ParameterType))
            return Activator.CreateInstance(typeof(S), lst) as S;
    }

    throw new TypeAccessException();
}

问题 2 已在此处得到解答,问题 3 仍然是个谜。

于 2012-11-13T20:15:56.530 回答