1

I have a method in which I send two arguments of the same type and I need to fold them. For example, if these are numbers, then return only the sum, and if the lines are the concatenation of these lines. How can I do it? And if I pass a type that cannot be folded, then I need to throw an exception.

public class Calcul<T>
{
    public static T Add(T c1, T c2)
    {
    }
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Dinopopik
  • 19
  • 2
  • 4
    Sounds like you might want to use overloads, not generics. How many types can T be? – Wai Ha Lee May 03 '19 at 15:31
  • Any types, the fact of the matter is that you can use any, but if only you can work with them. – Dinopopik May 03 '19 at 15:34
  • 1
    "For example, if these are numbers, then return only the sum, **and if the lines are the concatenation of these lines**." I've read the bold part several times and I still don't get what you're trying to say. – itsme86 May 03 '19 at 15:35
  • This is something like a calculator for all types of data. – Dinopopik May 03 '19 at 15:38
  • So what do you want to do if someone passes in two `HashSet` instances, or a `Transaction`, or a `Window`? How do you intend to "add" those things? – Servy May 03 '19 at 15:42
  • just adding the c1 and c2 will concatenate if they are string and sum them up if they are summable types. What would you do if c1 and c2 are objects? – haku May 03 '19 at 15:42
  • 1
    if they are objects, I will just throw an exception. I need to process only those types that I can handle. – Dinopopik May 03 '19 at 15:44
  • 2
    Don't make the method generic if it's not actually generic, and don't say the method can accept any type if it can't in fact accept any type. As you've already been told, if you want to handle a finite number of specific types, have overloads for each of those types. – Servy May 03 '19 at 15:46
  • Alas, I showed the teacher, but he said that it was not that. He said that it should be something like an abstract calculator where for each type T you can define the operation N – Dinopopik May 03 '19 at 15:49

4 Answers4

1

Servy said in a comment:

Don't make the method generic if it's not actually generic, and don't say the method can accept any type if it can't in fact accept any type. As you've already been told, if you want to handle a finite number of specific types, have overloads for each of those types.

to which you replied:

Alas, I showed the teacher, but he said that it was not that. He said that it should be something like an abstract calculator where for each type T you can define the operation N


You can have your method with that signature and no if blocks at all, but the Add method can't be static. You have to pass in a Func<T1, T2, TResult> where T1, T2, and TResult are the same (T):

public class Calculator<T>
{
    private readonly Func<T, T, T> _func;

    public Calculator(Func<T, T, T> func)
    {
        _func = func;
    }

    public T Add(T a, T b)
    {
        return _func(a, b);
    }
}

You'd use it like this:

Func<int, int, int> intAddition = (a, b) => a + b;
var intCalculator = new Calculator<int>(intAddition);
Console.WriteLine(intCalculator.Add(1, 2)); // writes 3

Func<string, string, string> stringAddition = (a, b) => a + b;
var stringCalculator = new Calculator<string>(stringAddition);
Console.WriteLine(stringCalculator.Add("Hello ", "world")); // writes "Hello world"

Online example: https://dotnetfiddle.net/8NOBsv


This way you get to specify the logic of the Add method, and you don't have loads of overloaded methods (or awful type-checking logic inside the method like if ( typeof(T) == typeof(string) ), etc.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
  • 1
    @ДинарВалитов I think this should answer your question. Can you add the details in the comments to the question and restructure it? – Narendran Pandian May 03 '19 at 16:21
0

You can typeof(T) to get the type information always. Using that, you can use conditional statements to work your way through the logic

Example:

var type = typeof(T);
if (type == int)
{ do something ;}

Generics are used for cases like : 2 different types following the same operations but taking different input types and output types. The underlying usage is that they have the same processes. If you are using type specific processes much, then its better to overload your functions to suit your need.

Reading more into your use case:

Try overloading methods.

private static int doSomething(int n1, int n2)
    {           
        return (n1) + (n2);  
    }

    private static float doSomething(float n1, float n2)
    {
        return (n1) - (n2);
    }
0

Here's a generic way that works as long as T supports the + operator. However, it uses runtime checking. As far as I can tell there is no way to use type constraints to check this at compile time.

Adapted from: https://stackoverflow.com/a/5997156/6713871

public class Calcul<T>
{
    public static T Add(T c1, T c2)
    {
        return (dynamic)c1 + (dynamic)c2;
    }
}
Chris Rollins
  • 550
  • 3
  • 9
0

As others have said you should probably use overloads. However it's possible to do something like this

static class Calc<T>
{
    public static T Add(T a, T b)
    {
        if (typeof(T) == typeof(int))
        {
            return (T)(object)((int)(object)a + (int)(object)b);
        }

        if (typeof(T) == typeof(uint))
        {
            return (T)(object)((uint)(object)a + (uint)(object)b);
        }

        throw new ArgumentOutOfRangeException($"Type {typeof(T).Name} is not supported.");
    }    
}

And call it with:

Calc<int>.Add(1 , 2); // returns 3
Calc<double>.Add(2d, 3d).Dump(); // throws exception
milan
  • 133
  • 6