Click here to Skip to main content
15,892,804 members
Articles / Programming Languages / C#
Tip/Trick

C# Generics with primary datatypes

Rate me:
Please Sign up or sign in to vote.
3.75/5 (5 votes)
6 Feb 2013CPOL2 min read 28K   8   6
C# Generics with primary datatypes.

Recently me and my friend discussed about Generics in C# and after a long discussion we agreed on one common definition, which is as below: 

Generics is a feature which is useful when you have a set of types going to perform some set of functions which are the same but the output differs from one type to another type.

Alternatively, we can say "whatever the type is, I want to be able to do some common set of operation(s)." The implementations of the operation are different, but the idea is the same. To understand this properly I created a console application in which I created a method which does addition as below.

C#
public T Add<T>(T t1, T t2)
{
    T t3 = t1 + t2;
    return t3;
}

So as per the generic definition, this should work but when I complied, I got the following compile time error:

Error 1 Operator '+' cannot be applied to operands of type 'T'.

First when I encountered the error I thought that it might be that I did something wrong. After sometime I realised that whatever you passed as a generic type it is converted to an object. So if I pass any primary data type it first gets boxed automatically and than the generic function take care of that. By following this fact if we apply +,- etc. kind of arithmetic operations on a primary data type, the generic function is not going to work because it gets converted to object, i.e., it is boxed.

To resolve the problem with the primary data types in generic functions I modified my above function as below.

C#
public T Add<T>(T val1, T val2)
{
    if (val1 == null)
        throw new ArgumentNullException("val1");
    if (val2 == null)
        throw new ArgumentNullException("val2");

    object n1 = val1,
           n2 = val2;

    if (val1 is byte)
        return (T)((object)((byte)n1 + (byte)n2));
    if (val1 is short)
        return (T)((object)((short)n1 + (short)n2));
    if (val1 is int)
        return (T)((object)((int)n1 + (int)n2));
    if (val1 is long)
        return (T)((object)((long)n1 + (long)n2));
    if (val1 is float)
        return (T)((object)((int)n1 + (int)n2));
    if (val1 is double)
        return (T)((object)((double)n1 + (double)n2));

    throw new InvalidOperationException("Type " + typeof(T).ToString() + " is not supported.");

}

As you can see, in the above code, first I check the type of the object and if the type of the object matches then I perform the function that does the add operation. Basically I am unboxing the parameter passed to the function.

Conclusion

In generics, primary data types are treated as boxed objects so when you are coding generics for primary data types beware that you need to convert the passed parameter in the primary data type, i.e., you need to unbox the values again.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India

Microsoft C# MVP (12-13)



Hey, I am Pranay Rana, working as a Team Leadin MNC. Web development in Asp.Net with C# and MS sql server are the experience tools that I have had for the past 5.5 years now.

For me def. of programming is : Programming is something that you do once and that get used by multiple for many years

You can visit my blog


StackOverFlow - http://stackoverflow.com/users/314488/pranay
My CV :- http://careers.stackoverflow.com/pranayamr

Awards:



Comments and Discussions

 
GeneralMy vote of 4 Pin
Abdisamad Khalif15-Sep-13 3:53
professionalAbdisamad Khalif15-Sep-13 3:53 
GeneralMy vote of 1 Pin
John Brett6-Feb-13 23:04
John Brett6-Feb-13 23:04 
GeneralMy vote of 2 Pin
Klaus Luedenscheidt6-Feb-13 19:36
Klaus Luedenscheidt6-Feb-13 19:36 
BugYour analysis of the difficulty is incorrect Pin
Matt T Heffron6-Feb-13 12:46
professionalMatt T Heffron6-Feb-13 12:46 
The error you got
Error 1 Operator '+' cannot be applied to operands of type 'T'.

trying to use the + operator on values in a generic function is not because the values are boxed. They aren't. In fact, one of the main advantages of generic functions is avoiding boxing of values.
The reason for the error is that the compiler has no way to know if the actual values passed (which will determine the type that T represents) actually implement the + operator.
You can improve the compiler's ability to know how to handle the values by using type parameter constraints.
As Hojjat Khodabakhsh mentioned in his comment, the dynamic type can help by deferring the resolution of the + operator until run-time. However, this will cause runtime errors if the method is called with arguments of a type that doesn't implement the + operator between two same-type values.
Consider:
C#
// constrain T to value types, so no null check required
public T Add<T>(T val1, T val2) where T : struct
{
    return (dynamic)val1 + val2;
}

This is better because val1 and val2 are constrained to value types so they can never be null. However, calling this with DateTime values is perfectly fine at compile time but will fail at run time since the + operator for DateTime does not take DateTime as the second operand. Likewise, passing any declared struct is legal at compile time but will fail at run time.
So for complete safety you still need to do some checking of the type of the passed arguments:
C#
private static readonly Type[] NumericTypes = new Type[]{
  typeof(byte), typeof(sbyte), typeof(short), typeof(ushort),
  typeof(int), typeof(uint), typeof(long), typeof(ulong),
  typeof(float), typeof(double), typeof(decimal)
};
// As above, constrain T to value types, so no null check required
public T Add<T>(T val1, T val2) where T : struct
{
  if (NumericTypes.Contains(typeof(T)))
    return (dynamic)val1 + val2;
  throw new InvalidOperationException("Non-numeric type " + typeof(T).FullName + " is not supported.");
}

I can use typeof(T) here even if this is called with different types at different times, because the compiler will generate code for each type of T as required by the various calls of Add().
Suggestionusing dynamic keyword Pin
Hojjat Khodabakhsh7-Nov-12 19:21
Hojjat Khodabakhsh7-Nov-12 19:21 
GeneralRe: using dynamic keyword Pin
wanjp20108-Nov-12 14:41
wanjp20108-Nov-12 14:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.