【问题标题】:Getting error while executing Ienumerable<Datarow>.Sum() method.执行 Ienumerable<Datarow>.Sum() 方法时出错。
【发布时间】:2010-08-19 12:02:47
【问题描述】:

为什么下面的代码不起作用?我收到以下错误。

无法将类型“V”隐式转换为 int。

private ObservableCollection<DataItem> method<T, V>(DataTable dt, SeriesItem seriesItem, FilterValues filter, ObservableCollection<DataItem> chart)
{
    var result = from t in dt.AsEnumerable()
                 group t by new { type = t.Field<T>(seriesItem.LabelMapping).ToString().ToUpper() } into g
                 orderby g.Key.type
                 select new
                 {
                     Item_Type = g.Key.type.ToString(),
                     Amount = seriesItem.IsSum 
                          ? g.Sum(s => s.Field<V>(seriesItem.ValueMapping)) 
                          : g.Count()
                 };

    foreach (var g in result) 
    { 
        chart.Add(new DataItem(g.Item_Type, double.Parse(g.Amount.ToString()))
                  { 
                      IsSum = seriesItem.IsSum, 
                      IsDisplayCurrency = seriesItem.IsDisplayCurrency 
                  }); 
    }
    return chart;
}

【问题讨论】:

  • seriesItem.ValueMapping 的类型是什么?就此而言,也许您可​​以粘贴 SeriesItem 的基本公共定义?
  • 行不通...这不是 C++ 模板。

标签: c# linq generics lambda


【解决方案1】:

问题是您试图对 V 类型的所有值求和。

s.Field&lt;V&gt;(...) 返回一个 V 类型的值,因此选择器匿名函数 s =&gt; s.Field&lt;V&gt;(...) 也返回一个 V 类型的值。但是,g.Sum(...) 需要一个返回以下类型之一的值的选择器函数:@ 987654324@、doublefloatintlong(或它们的可空对应物)。不可能从类型 V 隐式转换为任何这些类型。

如果值映射列始终属于特定类型,则显式使用该类型而不是泛型类型 V。

【讨论】:

    【解决方案2】:

    看看你的代码,我猜这段代码返回了一个 V 类型的值:

    s => s.Field<V>(seriesItem.ValueMapping)
    

    如果是这种情况,鉴于对 V 类型没有约束(它可以是任何东西、对象、字符串等),编译器将无法确定哪个重载的 Enumerable.Sum() 方法调用,因此编译器错误。

    假设 V 的类型仅在运行时已知(因此您不能简单地将 V 约束为 int/decimal/double 等)如何将委托添加到可用于从对象返回 int 的方法V型?例如:

    private ObservableCollection<DataItem> method<T, V>(DataTable dt, SeriesItem seriesItem, FilterValues filter, ObservableCollection<DataItem> chart, Func<V, int> convertV)
        {
            var result = from t in dt.AsEnumerable()
                         group t by new { type = t.Field<T>(seriesItem.LabelMapping).ToString().ToUpper() } into g
                         orderby g.Key.type
                         select new
                         {
                             Item_Type = g.Key.type.ToString(),
                             Amount = seriesItem.IsSum ? g.Sum(s => convertV(s.Field<V>(seriesItem.ValueMapping))) : g.Count()
                         };
    

    然后你将责任推给调用者(它会知道类型 T 和 V)来弄清楚如何将 V 转换为 int。

    【讨论】:

      【解决方案3】:

      g.Count() 返回一个整数

      IsSum ? g.Sum() : g.Count() 必须是整数

      所以g.Sum() 必须是一个整数

      所以V 必须是一个整数

      没有任何东西(除了这个推论)可以阻止 V 成为 decimal 或其他任何东西,因此会出现编译器错误消息。

      修复:以下任何一种:

      • 删除 V 并获取 int 结果
      • 删除g.Count()
      • 将 g.Count() 转换为 double 并将 V 的类型固定为 double。

      最后一个有额外的好处,您可以稍后在该方法中删除双重转换代码。


      @丹尼尔·伦肖

      List<decimal> source = new List<decimal>();
      int result = source.Sum<decimal>();  //compile error
        //Cannot implicitly convert type 'decimal' to 'int'
      

      【讨论】:

      • g.Sum() 可以返回任何可以隐式转换为 int 或 int 可以隐式转换为的类型
      猜你喜欢
      • 2016-02-01
      • 2012-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-22
      • 2015-10-26
      相关资源
      最近更新 更多