简体   繁体   中英

How to create a extension method to sum up a column of a generic constrained type in a datatable

Is something like the below possible?

    public static T Sum<T>(this DataTable dt, string columnName) 
        where T : IEnumerable<decimal>, IComparable<decimal>
    {            
        return (from c in dt.AsEnumerable()
                where !c.IsNull(columnName)
                select c.Field<T>(columnName)
                ).Sum();
    }

It feels like i'm almost there, but not quite :/

Just trying to sum up either decimal or int values in a column in datatable. Currently getting a compile error, however think this is due to the incorrect generic constraint.

There is no generic IEnumerable<T>.Sum() method; rather, there are discrete IEnumerable<decimal>.Sum() , IEnumerable<double>.Sum() , etc. methods (realized as extension methods in the Enumerable class ). So, the type of Sum that you call must be known at compile time .

For you, that means that you cannot make your method generic (unless you make a manual type distinction in your method). You will need to create one version for Decimal, one version for Double, etc. The version for Decimal, for example, could look like this (untested, since I don't have Visual Studio available right now):

public static decimal SumDecimal(this DataTable dt, string columnName) 
{            
    return (from c in dt.AsEnumerable()
            where !c.IsNull(columnName)
            select c.Field<decimal>(columnName)
            ).Sum();
}

You probably want:

where T : decimal

but that does not make sense to have a generic parameter then :)

Try this:

public static decimal Sum(this DataTable dt, string columnName) {
  return (
    from c in dt.AsEnumerable()
    where !c.IsNull(columnName)
    select c[columnName]
  ).Sum(value => Convert.ToDecimal(value));
} 

Your column type must be convertible to decimal .

I think this is more compact, though:

public static decimal Sum(this DataTable dt, string columnName) {
  return dt.AsEnumerable().
    Where(row => !row.IsNull(columnName)).
    Sum(row => Convert.ToDecimal(row[columnName]));
}

You can also create other versions for the other integral types supported by Sum ( double , float , int , long ).

Alternatively, the DataTable already supports this scenario :

public static T Sum<T>(this DataTable dt, string columnName) {
  var sum = dt.Compute("Sum(" + columnName + ")", "");
  if (sum == DBNull.Value) return default(T);
  return (T)Convert.ChangeType(sum, typeof(T));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM