-2

Say I have the following functions:

public int Compute(int a, int b, int c)
{   
    return (a + b +c)/3;
}

public double Compute(double a, double b, double c)
{
    return ((a + b + c) / 3.0) / 209;
}

I hope the difference is obvious. A double value needs to be divided by 209 (a constant value) while an integer is not.

What is the best way to combine these two functions in a single one using generics?

user366312
  • 16,949
  • 65
  • 235
  • 452
  • 5
    Generics are used to make operations … umm … generic. IOW, they are used to make operations not care about the types they are operating on. Your operation clearly *does* care, since it behaves differently. – Jörg W Mittag Jul 27 '18 at 15:38
  • 4
    I think the best way is to not do it at all & leave it as it is, is there a reason for requiring a generic version? – Alex K. Jul 27 '18 at 15:38
  • @AlexK., those two functions are **nearly** identical. I just want to keep my code clean. – user366312 Jul 27 '18 at 15:39
  • 2
    The code is cleaner when you leave it like that... – juliushuck Jul 27 '18 at 15:40
  • Personally I think its clean as it stands, Clean != slightly less code. If common operations within each were complex enough to warrant it you can create a helper method that they both call. – Alex K. Jul 27 '18 at 15:43
  • 2
    The signature can be made generic: public T Compute(T a, T b, T c). But since you do different operations with doubles than with ints, you'd have to check the type inside the generic method, which means it shouldn't be generic in the first place. Also, not all types support math operations, so it will fail on most non-numeric types. – Rufus L Jul 27 '18 at 15:47
  • Generic would not be so helpful here. You could export the shared part (`(a+b+c)/3`) to a different private function and then call it from both of these public functions, But this code is so simple that leaving it as it is, is the best it think. – Ofir Winegarten Jul 27 '18 at 15:48
  • 1
    Even extracting the part with `(a+b+c)/3` into a shared generic method would not be practical because C# has no way to constrain a generic type parameter to be an "arithmetic" one that allows things like `+` and `/`. If that is what you _really_ want to ask, it is not possible. – Jeppe Stig Nielsen Jul 27 '18 at 15:59
  • You could use something like [this](http://www.yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html) but seriously, just use 2 functions, generics is overkill here. – DavidG Jul 27 '18 at 16:09
  • Maybe something like `if (a % 1 == 0 && b % 1 == 0 && c % 1 == 0) return (a + b + c) / 3; else return ((a + b + c) / 3.0) / 209;` and use only the `double` method – Ivan García Topete Jul 27 '18 at 23:53

4 Answers4

2

I'm not sure it makes sense here. Generics are the approach to avoid writing the similar code for different object types.

But in your case, I don't see any similar code which could be generalized so keeping the functions different solves the task better.

Sergey Prosin
  • 711
  • 4
  • 11
1

Short Answer

You cannot turn it into one function.

Long Answer

The only common code you have is this:

return (a + b +c)/

You could use generics and do this at best (not possible with C#):

public static T Compute<T>(T a, T b, T c, T divisorSmall, int divisor) 
{
    return ((a + b + c) / divisorSmall) / divisor;
    // Results in compiler error: Error CS0019  Operator '+' cannot be 
    // applied to operands of type 'T' and 'T'  
}

and use it like this:

Compute(1, 2, 3, 3, 1); // For integers
Compute(1.0, 2.0, 6.0, 3.0, 209); // For doubles

But you cannot do that because you cannot restrict the type T to support arithmetic operation or restrict T to be numeric.

Also, even if it was possible, you do not gain much in this specific case because look how clumsy the usage looks in my hypothetical solution.

CodingYoshi
  • 25,467
  • 4
  • 62
  • 64
0

You shouldn't do it with generics, but you can test if a, b and c are ints and then select your operation:

private double Compute(double a, double b, double c)
{
    /*         check if a, b and c are integers         int if true          double if false    */
    return (a % 1 == 0 && b % 1 == 0 && c % 1 == 0) ? (a + b + c) / 3 : ((a + b + c) / 3.0) / 209;
}

[TestMethod()]
public void Int()
{
    int a = 1;
    int b = 2;
    int c = 3;
    int result = (int)Compute(a, b, c);

    int expected = (1 + 2 + 3) / 3;

    Assert.AreEqual(expected, result);
}

[TestMethod()]
public void Double()
{
    double a = 1.1;
    double b = 2.2;
    double c = 3.3;
    double result = Compute(a, b, c);

    double expected = ((1.1 + 2.2 + 3.3) / 3.0) / 209;

    Assert.AreEqual(expected, result);
}

Both tests are passing

  • There is no point in doing this: Why would someone pass `int` to a method whose signature expects `double`? Sure this is doable but this is more of hack than anything else. As a good programmer, you need to program against an interface (signature) and not against the implementation of the method. – CodingYoshi Jul 28 '18 at 15:48
0

I have an idea. I can create a method generic which receives an Delegate for each case int and double. This version fiddle works https://dotnetfiddle.net/Q15bYK

    public static void Main()
    {   
        Func<double,double,double,double> x = (d1,d2,d3) => {return ((d1 +d2 + d3)/ 3.0) / 209;};

        Func<int,int,int,int> y = (i1,i2,i3) => {return (i1 + i2 + i3)/ 3;};

        var rsDouble = Compute<double>(1.0,2.0,3.0,x);
        Console.WriteLine(rsDouble);

        var rsInt = Compute<int>(1,2,3,y);
        Console.WriteLine(rsInt);

    }

    public static T Compute<T>(T a, T b, T c, Func<T,T,T,T> action)
    {
        return action(a,b,c);
    }

But this seems my answer make complicated the situation and I agree with other answers, generics are used to write the similar code for different object types, not to write different code for each parameters.

Antoine V
  • 6,998
  • 2
  • 11
  • 34