【问题标题】:How can i create a c# method that will return the same collection type as as argument with a different element type?如何创建一个 c# 方法,该方法将返回与具有不同元素类型的参数相同的集合类型?
【发布时间】:2016-07-12 15:54:21
【问题描述】:

基本上与this question 中的完全一样,但在c# 中。

我想要这样的东西:

public IList<double> DoSomething(IList<string> strings) {
    //something
}

但我宁愿输入它以便提前知道返回值,这样我就不必强制转换或函数之外的任何东西。我该怎么做?

有没有通用的方法,

public ListType<double> DoSomething<ListType>(ListType<string> strings) where ListType : ???{

要设置吗?

【问题讨论】:

  • 你可以使用 Linq 来做到这一点。
  • @EricLinde 你能告诉我答案吗?以及是否处理返回集合类型匹配输入集合类型的问题?

标签: c# generics


【解决方案1】:

C# 不能完全满足您的要求,但最接近的应该是:

public TList2 DoSomething<TList1, TList2>(TList1 strings) 
    where TList1 : IEnumerable<string>
    where TList2 : ICollection<decimal>, new()
{
    var result = new TList2();
    foreach (var s in strings)
    {
        result.Add(decimal.Parse(s));
    }
    return result;
}

还有一个例子:

var input = new HashSet<string>(new[] { "1", "2", "3"});
List<decimal> output = DoSomething<HashSet<string>, List<decimal>>(input);

【讨论】:

  • 这就是我所担心的。所以我没有办法在不诉诸运行时检查的情况下强制它们成为相同的集合类型?
  • 为什么需要它们?您如何使用输入,以便它需要一些模糊(但通用)的集合类型?为什么不直接使用IEnumerable&lt;string&gt; 作为输入类型?
  • 我更希望它与输入的内容保持一致。
【解决方案2】:

您可以使用 Linq 来执行此操作。

例如,如果你只想解析为 double 你会这样做:

List<double> result = strings.Select(double.Parse).ToList()

您可以使用任何其他方法而不是 double.Parse 发送:

List<double> result = strings.Select(DoSomethingWithOneItem).ToList()

double DoSomethingWithOneItem(string item) {
  //your conversion logic
}

不幸的是,例如 IList&lt;TInput&gt;IList&lt;TOutput&gt; 之间没有任何关系可以用来提供帮助,因此您需要指定输入和输出列表类型,这在一般形式中变得有点麻烦:

IList<string> strings  = new List<string> {"1.1", "2.2", "3.3"};
IList<decimal> result = strings.ConvertToSameListType((Func<string, decimal>)decimal.Parse, () => new List<decimal>());

public static class EnumerableExtensioncGeneralVersion
{
    public static TOutputList ConvertToSameListType<TInputList, TOutputList, TInput, TOutput>(this TInputList source, Func<TInput, TOutput> itemConversion, Func<TOutputList> outputListConstructor)
        where TInputList : IEnumerable<TInput>
        where TOutputList : ICollection<TOutput>
    {
        TOutputList result = outputListConstructor();
        foreach (TOutput convertedItem in source.Select(itemConversion))
        {
            result.Add(convertedItem);
        }
        return result;
    }
}

如果您只需为您想要支持的每种喜爱的集合类型指定一种扩展方法,就可以更好地使用转换:

//Seting up inputs
IList<string> strings  = new List<string> {"1.1", "2.2", "3.3"};
IEnumerable<string> enumerableStrings = strings.Select(x => x);
ObservableCollection<string> observableStrings = new ObservableCollection<string>(strings);

//Converting
IList<decimal> resultList = strings.Convert(decimal.Parse);
IEnumerable<decimal> resultEnumerable = enumerableStrings.Convert(decimal.Parse);
ObservableCollection<decimal> observableResult = observableStrings.Convert(decimal.Parse);

public static class EnumerableExtensions
{
    public static IList<TOutput> Convert<TInput, TOutput>(this IList<TInput> source, Func<TInput, TOutput> itemConversion)
    {
        return source.Select(itemConversion).ToList();
    }
    public static IEnumerable<TOutput> Convert<TInput, TOutput>(this IEnumerable<TInput> source, Func<TInput, TOutput> itemConversion)
    {
        return source.Select(itemConversion);
    }
    public static ObservableCollection<TOutput> Convert<TInput, TOutput>(this ObservableCollection<TInput> source, Func<TInput, TOutput> itemConversion)
    {
        return new ObservableCollection<TOutput>(source.Select(itemConversion));
    }
}

【讨论】:

  • 这意味着我每次想使用它时都需要这样做。我想要更像felix-b's answer 的东西。
  • 据我了解,问题是关于在方法的通用参数中指定具体的集合类型,而不是关于将一​​个集合转换为另一个集合。
  • 是的,如果您希望输出列表类型始终与输入列表类型匹配,那么您需要更像@felix-b 建议的内容
  • @EricLinde felix 没有强制它们匹配,它只允许您定义输入和输出类型(虽然我不知道为什么需要输入类型)。
  • 现在更新了我的答案,希望能更接近您的需要。
猜你喜欢
  • 2021-11-11
  • 2013-07-27
  • 1970-01-01
  • 2016-05-13
  • 2011-09-11
  • 1970-01-01
  • 2016-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多