【问题标题】:Sum method extension for IEnumerable<TimeSpan>IEnumerable<TimeSpan> 的 Sum 方法扩展
【发布时间】:2016-02-01 11:01:49
【问题描述】:

编辑:对于我的变量名称造成的混淆,我深表歉意。 TotalHours 和 Hours 确实是 TimeSpan,我试图总结 TimeSpan,而不是 Timespan 的 Hours 属性。

我目前正在使用它来汇总表中的 Hours 列(TimeSpan 类型):

TotalHours = MainGridTable.Select(x => x.Hours).Aggregate((x,y) => x.Add(y));

我试过像这样对 IEnumerable 进行 Sum 扩展,但它不起作用:

public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> selector) 
{            
    return source.Aggregate(((t1, t2) => t1.Add(t2));         
}

我搜索了.NET源代码,发现现有的Sum方法返回为:

return Enumerable.Sum(Enumerable.Select(source, selector));

然后我尝试像这样对 Enumerable 进行非泛型 Sum 扩展,但上面的 return 语句没有识别它,它只是不断要求十进制参数。

    public static TimeSpan Sum(this IEnumerable<TimeSpan> source) {
        TimeSpan sum = new TimeSpan(0, 0, 0);
        foreach (TimeSpan v in source) {
            if (v != null) sum.add(v);
        }
        return sum;
    }

我不太精通函数、扩展和泛型。我的错误是什么,我该如何完成这项工作?

【问题讨论】:

  • 请发帖minimal reproducible example。您当前的代码有几个不相关的错误,这些错误可能不会出现在您的真实代码中。这使得很难说出实际问题是什么。
  • TotalHours = MainGridTable.Sum(x => x.Hours),如果您只想对 IEnumerable 中每个 TimeSpan 的值求和。你想要什么超出小时的总和
  • @MrinalKamboj 我认为HoursTimeSpan 类型的属性,并且OP 没有对TimeSpan.Hours 属性求和。还是我误解了你的评论?
  • @hvd 据我了解,OP 希望为给定的 TimeSpan 添加 Hours 或 TotalHours 属性,这就是 Select 和 Aggregate 所做的,稍后可以将其转换为 TimeSpan 作为最终结果
  • @MrinalKamboj 是的,这完全不是我认为 OP 正在尝试的。我认为 OP 有class MainGridRow { ... public TimeSpan Hours { get { ... } set { ... } } ... }。 OP 从MainGridTable 中选择这一事实强烈地向我暗示这是一个类似DataTable 的结构,具有多列,其中一个可能具有TimeSpan 类型。 :)

标签: c# linq ienumerable extension-methods


【解决方案1】:

编辑感谢您阐明您要实现的目标。我仍然不确定我是否真的明白了,所以这将是我最后一次尝试:-)

    public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, 
         Func<TSource, TimeSpan> selector) 
    {
        var ts = new TimeSpan();
        return source.Aggregate(ts, (current, entry) => current + selector(entry));
    }

我不确定您试图通过 TotalHours 表示什么,因为显然,以总小时数表示的多个时间跨度的总和(可能包括小时、分钟、天、秒等)是另一回事,就像总结一些时间跨度的Hours 属性一样。我决定,您的意思是总结完整的实例 - 您可以从生成的 TimeSpan 中访问所需的 TotalHours 等信息。

TimeSpan 是不可变的,就像DateTime 一样,一个常见的问题是,您需要使用Add 方法的结果。

public static TimeSpan Sum(this IEnumerable<TimeSpan> source) {
    TimeSpan sum = new TimeSpan(0, 0, 0);
    foreach (TimeSpan v in source) {
        sum = sum.Add(v);
    }
    return sum;
}

另外请注意,TimeSpan 是一个值类型 (struct),因此永远不能使用 null。因此,在您的代码中检查 null 是多余的。

LINQ 版本如下所示:

    public static TimeSpan Sum(this IEnumerable<TimeSpan> source)
    {
        TimeSpan sum = new TimeSpan(0, 0, 0);
        return source.Aggregate(sum, (current, v) => current.Add(v));
    }

同样,您需要使用Add 方法的结果。

【讨论】:

  • 我添加了一个编辑来尝试消除混乱。我确实想总结 TimeSpan,而不是他们的 Hours 属性。问题是我正在尝试创建一个可以应用于任何 IEnumerable 的 Sum 扩展,并使用 lambda 来选择每个枚举项的 TimeSpan 属性,从而返回另一个 TimeSpan。感谢您对 TimeSpan 不可变性的提醒,这会让我以后头疼。
  • 感谢您的帮助,这行得通。我还在相关搜索中偶然发现了this answer,我不敢相信我之前没有找到这个。我只是想不通如何使用函数的选择器参数。
猜你喜欢
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
  • 1970-01-01
  • 2018-09-06
相关资源
最近更新 更多