views:

55

answers:

3

Why isn't the below code working? I am getting an error.

It says 'Cannot implicitly convert type 'V' to 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;
    }
A: 

g.Count() returns an int

IsSum ? g.Sum() : g.Count() must be an int

so g.Sum() must be an int

so V must be an int

There is nothing (other than this deduction) that stops V from being a decimal or anything else, hence the compiler error message.

To fix: Any of these:

  • remove V and get int results
  • remove g.Count()
  • cast g.Count() to double and fix V's type as double.

This last one has the added benefit that you can remove the double conversion code later in the method.


@Daniel Renshaw

List<decimal> source = new List<decimal>();
int result = source.Sum<decimal>();  //compile error
  //Cannot implicitly convert type 'decimal' to 'int'
David B
`g.Sum()` can return any type that can be implicitly cast to an int or to which int can be implicitly cast
Daniel Renshaw
A: 

The problem is that you're trying to sum over all values of type V.

s.Field<V>(...) is returning a value of type V so the selector anonymous function s => s.Field<V>(...) is also returning a value of type V. However, g.Sum(...) requires a selector function that returns values of one of the following types: decimal, double, float, int, long (or their nullable counterparts). It is not possible to implicitly cast from type V to any of those types.

If the value mapping column is always of a particular type then use that type explicitly instead of the generic type V.

Daniel Renshaw
A: 

Looking at your code, I'm guess this bit of code returns a value of type V:

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

if that's the case, given that there's no constraint on the type V (it could be anything, object, string, etc. etc.) the compiler won't be able to figure out which of the overloaded Enumerable.Sum() method to invoke, hence the compiler error.

Assuming that V's type is known only at runtime (so you can't simply constraint V to int/decimal/double, etc) how about add a delegate to the method which you can use to return an int from an object of type V? e.g:

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()
                     };

then you push the responsibility to the caller (which would know the types T and V) to figure out how to convert V to an int.

theburningmonk