Skip to main content
 首页 » 编程设计

c#之选择集合的返回类型 : Is there a way to return the same type that is provided

2024年01月01日33Free-Thinker

在为 API 编写通用扩展方法时,我在选择集合的返回类型时进退两难。我已经阅读了关于返回什么集合类型以及设计选择应该是什么的讨论。我通常更喜欢接受最基本的类型作为参数并返回最丰富的类型。

我现在正在考虑返回提供的相同类型。不管这是否是一个好的选择,有没有一种方法可以以一种易于使用的方式来完成?

例如。让我有这个:

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

现在我想返回一个 IEnumerable , ICollection或 IList取决于参数 source .所以我对此做了一些修改。

 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 
 } 

我面临的主要问题是我无法调用函数 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. 正如 Marc 指出的那样,转换并非在任何地方都有效。有没有更好的方法来返回 S 类型的集合?来自List<T>如果S反正是IEnumerable<T> ?

  2. 是否可以在不指定类型的情况下自动推断类型?

  3. 还有为什么是d.Generize()给予 definition not found错误而不是 types cannot be inferred错误?

编辑:

虽然IEnumberable<T>可以是任何具体类型,在我的例子中,它只会是通常找到的类型,如 T[]或 List<T>或者更多来自 Linq命名空间。处理它们并不容易。只是指出原来的问题现在对我来说没有意义。谢谢大家..!

请您参考如下方法:

警告:好的,我的问题不是很好,而且我的想法有点愚蠢。这只是为了回答我的帖子,我不推荐它。我将依靠返回适当的 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(); 
} 

Question 2 has been answered here问题 3 仍然是个谜。