HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Computing value sums in a custom grid

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
gridvaluecustomsumscomputing

Problem

I have written a helper method which computes the sum of values in some custom grid, given the column indexes. The method appears to work (for a decimal - as Anthony pointed out, I need to test this further), but I am not at ease with the following conversions:

decimal valIfNull = (decimal)(object)valueIfNull;
return (T)(object)sum;


They seem too indirect, but Convert.ChangeType also returns an object type, so another cast is needed anyway. Also, I believe that Convert.ChangeType can convert a string such as "123.456" into a proper decimal value, but this is not the behavior I want in this case. I would like to see an invalid cast exception in that case. So, is what I have good enough, or is there a better way?

private T SumColumns(T valueIfNull, params short[] columnIndexes)
        where T : struct, IConvertible
    {
        // Since we do not know what exactly T is, we will compute things as if it was a decimal.
        // If this works reasonably well, then this trick should be used elsewhere.

        // I am not sure if this is the best way to go about casting
        decimal valIfNull = (decimal)(object)valueIfNull;

        // Here this.GetCurrentRowValue is another generic function I wrote ...
        decimal sum = columnIndexes.Select(columnIndex => this.GetCurrentRowValue(columnIndex: columnIndex, valueIfNull: valIfNull)).Sum();
        return (T)(object)sum;
    }

Solution

You've already placed a constraint on the first parameter that it should be IConvertible, so the methods of that interface is available to you.

decimal decimalValueIfNull = valueIfNull.ToDecimal(CultureInfo.InvariantCulture);


Converting back to the generic type won't be as straight forward. When casting between an object and a value type, no conversions will be made and you are just boxing/unboxing the value. Since you have a constraint that the type be a value type, the casts won't really work here. In fact, I don't think it's even possible to do so generically. If a conversion exists from decimal to the type you wouldn't be able to express that here. And you won't be able to use the Convert class to do the conversion, there's no way to "add" conversions to existing convertible types.

Your best (and probably only) option would be to convert it to a dynamic variable and let the runtime figure out whether or not that conversion exists. That way if you have a custom ValueType here that has an implicit or explicit conversion from a decimal, it will be used.

return (T)(dynamic)sum;


If you know for sure that the types that are used here can be converted from a decimal, then you could convert back using IConvertible.ToType().

return ((IConvertible)sum).ToType(typeof(T), CultureInfo.InvariantCulture);

Code Snippets

decimal decimalValueIfNull = valueIfNull.ToDecimal(CultureInfo.InvariantCulture);
return (T)(dynamic)sum;
return ((IConvertible)sum).ToType(typeof(T), CultureInfo.InvariantCulture);

Context

StackExchange Code Review Q#11156, answer score: 4

Revisions (0)

No revisions yet.