6

I have a method that determines the min and max of a column in a DataTable:

public void GetMinMaxRange( DataTable data, string valueColumnName )
{
   var min = data.AsEnumerable().Min(m => m.Field<double>(valueColumnName));
   var max = data.AsEnumerable().Max(m => m.Field<double>(valueColumnName));
}

I want to refactor this to be:

public void GetMinMaxRange( DataTable data, string valueColumnName )
{
   DataColumn column = data.Columns[valueColumnName];
   var min = data.AsEnumerable().Min(m => m.Field<column.DataType>(valueColumnName));
   var max = data.AsEnumerable().Max(m => m.Field<column.DataType>(valueColumnName));
}

I need to determine the datatype and use it instead of hard-coding m.Field<double>. How to do this?

UPDATE As to why I want to calculate the difference between the min and the max

    public static double/decimal/int GetMinMaxRange<T>(DataTable data, 
          string valueColumnName) where T : IComparable<T>
    {
        DataColumn column = data.Columns[valueColumnName];
        var min = data.AsEnumerable().Min(m => m.Field<T>(valueColumnName));
        var max = data.AsEnumerable().Max(m => m.Field<T>(valueColumnName)); ;
        return max - min;
    }
O.O
  • 10,083
  • 18
  • 83
  • 166

3 Answers3

6

Simply creating this as a generic should work:

public void GetMinMaxRange<T>( DataTable data, string valueColumnName ) 
                                                             where T : IComparable<T>
{
   DataColumn column = data.Columns[valueColumnName];
   var min = data.AsEnumerable().Min(m => m.Field<T>(valueColumnName));
   var max = data.AsEnumerable().Max(m => m.Field<T>(valueColumnName));
}

Which you would then use as:

GetMinMaxRange<MyType>(dataTable, valueColumnName);
Jamie Dixon
  • 49,653
  • 18
  • 119
  • 157
2

If you want to this on runtime, you can't use generics. You can rewrite your method like this:

public void GetMinMaxRangeTest(DataTable data, string valueColumnName)
{
    DataColumn column = data.Columns[valueColumnName];
    var min = data.AsEnumerable().Min(m => Convert.ChangeType(m[valueColumnName], column.DataType));
    var max = data.AsEnumerable().Max(m => Convert.ChangeType(m[valueColumnName], column.DataType));
}

I have tested this on a list, like this:

List<string> num = new List<string>() { 
    "1", "2", "3", "-1", "11", "10", "100"
};
var min = num.AsEnumerable().Min(m => Convert.ChangeType(m, typeof(int)));

and it yields the proper result: -1.

AlexB
  • 730
  • 4
  • 13
  • I get 'Object must implement IConvertible.' error for a DataTable rather than a List – O.O Sep 12 '11 at 16:54
  • What type does m[valueColumnName] have? double, decimal, int and string are all IConvertible so m[valueColumnName] having a value of this type can't be the problem – AlexB Sep 12 '11 at 17:09
1

You can't do this so simple. column.DataType will be a SqlDbType and since it will only be known at runtime so the compiler can't verify that it is IComparable.

Henk Holterman
  • 236,989
  • 28
  • 287
  • 464