Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C#4.0
Could someone help me to understand if what I want to do is possible?
 
I have a simple generic method:
 
public T DivideByTwo<T>(T number)
{
     T two = (T)Convert.ChangeType(2, typeof(T));
 
     T result = DIVIDE(number, two);
 
     return result;
}
 
I can call it like this no problem:
 

ParallelNumber<double> parallelNumber = new ParallelNumber<double>();
 
double result = parallelNumber.DivideByTwo(3);
 
And of course I can use int,uint etc etc.
 
But I cannot call it as follows:
 
ParallelNumber<BigInteger> parallelNumber = new ParallelNumber<BigInteger>();
 
BigInteger result = parallelNumber.DivideByTwo(3);
 
The line which fails is:
 
T two = (T)Convert.ChangeType(2, typeof(T));
 
Throws InvalidCastException. Invalid cast from System.Int32 to System.Numerics.BigInteger
 
Can I make my method generic enough to handle BigInteger?
 
(The DIVIDE function just takes two generic arguments and returns a generic)
Posted 11-Feb-13 7:10am
Edited 11-Feb-13 7:12am
ProgramFOX127.4K
v2
Comments
Sergey Alexandrovich Kryukov at 11-Feb-13 12:49pm
   
You are posing an interesting problem. I vote 4 for the answer.
 
You are trying to create a numeric library (even if this is one function, but essentially this is what it is) abstracted from the concrete primitive numeric types.
I can tell you that existing solutions of this problems for .NET are all quite ugly. This is one of the few fundamental limitations of the .NET, related to 1) lack of fully-fledged meta-types, 2) limitation of generic constraints (there is not a base class or interface "numeric type", and primitive types cannot be used for generic constraints).
 
One solution is to pass two generic parameters: numeric type and class implementing the interface with common arithmetic operations, so the generic constraint will be this interface. If this numeric type and interface implementation do not match, nothing can prevent it, it will compile but fail to work. And this is the best solution...
 
If you are really interested, I can explain it all, with the available solution, but my advice is to give up. Seriously.
—SA
Mehdi Gholam at 11-Feb-13 13:25pm
   
Agreed, some abstract problems are not worth the effort when there are simpler ways to divide by 2 :)
Sergey Alexandrovich Kryukov at 11-Feb-13 14:33pm
   
Well, actually, making libraries abstracted from the type is extremely good to have, but as to numeric... Even C++ puts .NET to shame. With .NET, it hardly pays off, well, may be for some specific numeric calculation topics...
—SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

Hi,
 
Thanks for all the answers. Here's my solution so far. It is simpler to code than the accepted solution recommended by AspDotNetDev, and I think would be faster. Can anyone advise me further or is what I have as good as it will get?
 
I have a generic class defined as follows:
 
 public class ParallelNumber<T>
 {
     private T GENERIC_TWO;
 
     private Func<T,T,T> DIVIDE = null;
 
      public ParallelNumber()
      {
            CreateDivideFunction();
 
            if (typeof(T) == typeof(BigInteger))
            {
                GENERIC_TWO = (T)Convert.ChangeType((BigInteger)2, typeof(T));
            }
            else
            {
                GENERIC_TWO = (T)Convert.ChangeType(2, typeof(T));
            }
      }
 
      private void CreateDivideFunction()
      {
            ParameterExpression paramA = Expression.Parameter(typeof(T), "a"), paramB = Expression.Parameter(typeof(T), "b");
 
            BinaryExpression body = Expression.Divide(paramA, paramB);
 
            DIVIDE = Expression.Lambda<Func<T, T, T>>
  Permalink  
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 4

 HERE's the rest of the text which the preview ingored :(
 
(body,paramA,paramB).Compile();
       }
 
       public T DivideByTwo(T number)
       {
            T result = DIVIDE(number, GENERIC_TWO);
 
            return result;
       }
 }
 
The last function DivideByTwo is the one which can now be called with any numeric type.
 
Would anyone else endorse this method and if so would they suggest improvements or would anyone go down a completely different root.
 
This method takes about 100 times longer to run than one written using (say) uint instead of generics. Can I hope to match performance using generics instead on (say) uint.
 
It would be ideal if at runtime, after having used the above function as follows:
 
ParallelNumber<uint> parallelNumber = new ParallelNumber<uint>();
uint d = parallelNumber.DivideByTwo(50);
 
it ran as fast as calling the function written with uint instead of generics. But then of course it ran slower when called as:
 
ParallelNumber<BigInteger> parallelNumber = new ParallelNumber<BigInteger>();
BigInteger d = parallelNumber.DivideByTwo(50);
 
Thanks for any help,
Mitch.
  Permalink  
Comments
RajeshRaushan at 19-Feb-13 4:29am
   
You are creating dynamic type on your own. The problem here is with the creation. Every time you create an Instance it creates a code snippet and compile - all these just to get a proper function definition for the supplied T type.
 
Just maintain the private Func<T,T,T> as static. In the Instance constructor see if it is null.
If so do what you are doing - otherwise no need to create and compile that once again. the function would be there already for the supplied type.
 
This way for a given type T - you will not end-up creating function dynamically every time.
 
C# generics are different from C++ templates. It doesn't provide the exact thing here - but this kind of usage in real world example is extremely rare. Also this isn't best way how we should work with Generics.
It will work for numeric types - but if somebody starts using like ParallelNumber<string> or ParallelNumber<employee>.
 
It will throw a runtime exception and that is not c# way of programming for sure. C++ is a language for intelligent developers - where a lot depend upon intelligence of the programmer - where as C# is a intelligent language in itself. It puts best effort to make sure things doesn't get wrong and surprises are not travelling directly to end-user.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

I recommend the following approach.
 
  1. Detect if Convert.ChangeType will work. You might just try it and catch the exception (that'd be the easiest way). However, there may be a way to use IConvertible to check the conversion without an exception being thrown. I'll leave this to you to dive deeper into.
  2. If Convert.ChangeType doesn't work, use reflection to check if the type has a constructor that accepts an integer. You can then use reflection to create an instance of that type and pass the integer to the constructor. This may also be possible with expression trees, but I'm not really sure how that works (though that may be a more optimal approach).
  3. If there is no appropriate constructor, you may want to use reflection to check if there is an implicit conversion operator from an int, then use reflection to perform the assignment to a new instance of the type.
  Permalink  

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

  Print Answers RSS
0 BillWoodruff 300
1 Mathew Soji 274
2 Afzaal Ahmad Zeeshan 268
3 DamithSL 225
4 Sergey Alexandrovich Kryukov 205
0 OriginalGriff 6,249
1 Sergey Alexandrovich Kryukov 5,853
2 DamithSL 5,183
3 Manas Bhardwaj 4,673
4 Maciej Los 3,865


Advertise | Privacy | Mobile
Web03 | 2.8.1411019.1 | Last Updated 13 Feb 2013
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100