0

I am attempting to write this function in a generic manner so that it can handle float, double, decimal, or int.

It works except that the statement (increment * ti) gives: "Operator * cannot be applied to operands of type T and int."

public static List<T> RangeIncrement<T>(T start, T end, T increment)
{
    T range = (((dynamic)end - (dynamic)start) / increment) + 1;

    if (TryCast(range, out int endRange))
    {
        return Enumerable
            .Repeat(start, endRange)
            .Select((tr, ti) => tr + (increment * ti))
            .ToList();
    }

    return null;
}
Ivan
  • 7,448
  • 14
  • 69
  • 134
  • Did you try casting `increment` to `dynamic` like you did at the top to get the range? What happens when I call this function with `string`? – Ron Beyer Jun 26 '19 at 19:03
  • 5
    Really though I think you are abusing generics and `dynamic` here though. You should write it once with the widest type and then cast or convert for the lower types with method overloading. You're opening yourself up to a lot of runtime errors when somebody calls it with something that doesn't have those operators defined. – Ron Beyer Jun 26 '19 at 19:05
  • 2
    People [keep trying to do this](https://stackoverflow.com/questions/828807/) and always run in to the problem that int, double, decimal, et al. are different data types with different ranges and behaviors. What do you expect to happen when you add a double that is not representable as a decimal to a decimal that is not representable as a double? Do not do this; create your own value type that implements the range and behavior you want and do not try to reconcile those of a bunch of other types. You can't. – Dour High Arch Jun 26 '19 at 19:09
  • I can add where T : struct type constraint to forbid string. – Ivan Jun 26 '19 at 19:15
  • @Ivan How do you multiply `DateTime.Now` by `true`? – 15ee8f99-57ff-4f92-890c-b56153 Jun 26 '19 at 19:21
  • You can use `where T: struct`, but it doesn't really solve the problem @Ron Beyer was pointing out. What happens if I call this method with `Guid` as the type parameter? `bool`? A custom `struct` that doesn't overload the arithmetic operators? As others have said, this doesn't seem like a good candidate for a generic method. – Joshua Robinson Jun 26 '19 at 19:24

1 Answers1

3

There are only a handful of types on which you can perform multiplication, and many are implicitly convertible to others. Instead of declaring a generic type T which could be pretty much anything and may or may not support multiplication, you could just write overloads that cover all of those options.

This chart shows the implicit conversions. Based on that, if you write your methods to support int, double, and decimal, that should cover everything.

In the process of testing you might find that it works as expected for one type but not for another. I'd write unit tests for all three of those types.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62