multiply two objects

  • Thread starter Thread starter Tigger
  • Start date Start date
T

Tigger

I have a method that is passed two objects and it needs to return an object
that represents those two objects multiplied together.

public object Multiply(object a, object b)
{
return a * b;
}

The objects can be any type of number and I would like it to do the maths in
the most efficient and accurate way.

e.g. if both numbers are double, they are multipled as doubles and a double
is returned.

Is there any way to do this in C#?

Tigger
 
I have a method that is passed two objects and it needs to return an object
that represents those two objects multiplied together.

public object Multiply(object a, object b)
{
return a * b;

}

The objects can be any type of number and I would like it to do the maths in
the most efficient and accurate way.

e.g. if both numbers are double, they are multipled as doubles and a double
is returned.

Is there any way to do this in C#?

To be honest, the simplest (if least aesthetically appealing) way of
doing this is simply to have lots of overloads, one for each numeric
type.

Jon
 
I almost replied the same... but for that to work, you'd either need
to know the types in the calling code (so the compiler can resolve),
or you'd have to use reflection based on a.GetType() and b.GetType().
The latter isn't very appealing, and the former, well, in that case
couldn't you just use "a * b" in the calling code, rather than
Multiply(a,b)?

Just a thought...

Marc
 
I almost replied the same... but for that to work, you'd either need
to know the types in the calling code (so the compiler can resolve),
or you'd have to use reflection based on a.GetType() and b.GetType().
The latter isn't very appealing, and the former, well, in that case
couldn't you just use "a * b" in the calling code, rather than
Multiply(a,b)?

Just a thought...

True, true. I think it's *got* to use reflection really, hasn't it, if
the given signature is the desired one.
I think I'd still have the appropriate overloads, but then do the same
sort of work that the compiler usually would, working out the right
conversion to use etc.

I can't see how this is going to be terribly efficient...

Jon
 
A tedious branch (below) might be an option... certainly faster than
reflection, but a nightmare to maintain and ugly as sin... but then
again, all those overloads would be similarly tedious...

Of course, if you know all the values are likely to be within the
range of decimal (as an example), then perhaps just use decimal
arithmetic throughout ;-p

if(a is decimal) {
if(b is decimal) {
return ((decimal)a)*((decimal)b);
} else if (b is int) {
return ((decimal)a)*((int)b);
} ...
} else if (a is int) {
if(b is decimal) {
return ((int)a)*((decimal)b);
} ...
} ...
throw new NotSupportedException();

Marc
 
Jon Skeet said:
To be honest, the simplest (if least aesthetically appealing) way of
doing this is simply to have lots of overloads, one for each numeric
type.

Jon
Quick reply!

Unfortunately that solution won't work in my case. The way I use it is a bit
like this....

int a = 56;
double b = 78.0;

object oa = a;
object ob = b;

object c = Multiply(oa,ob);

As I am passing objects into the method I have to implement an object based
overload to make it compile. And this is the one that always get used, even
if I create many other overloads.

I've come across this sort of issue before and ended up doing lots of "is"
tests.

Im this case it will be many, and I don't want to have to re workout all the
correct type conversions. e.g. int * double = double, float * decimal = ???

And I have to do this for +-*/

Tigger
 
Marc Gravell said:
A tedious branch (below) might be an option... certainly faster than
reflection, but a nightmare to maintain and ugly as sin... but then again,
all those overloads would be similarly tedious...

Of course, if you know all the values are likely to be within the range of
decimal (as an example), then perhaps just use decimal arithmetic
throughout ;-p

if(a is decimal) {
if(b is decimal) {
return ((decimal)a)*((decimal)b);
} else if (b is int) {
return ((decimal)a)*((int)b);
} ...
} else if (a is int) {
if(b is decimal) {
return ((int)a)*((decimal)b);
} ...
} ...
throw new NotSupportedException();

Marc

My current solution is like this (actual code) ...

protected override object Rule_MultExp_Times(Rule_MultExp_Times rule)
{
object left = this.Do(rule.Left); // Do returns an object
object right = this.Do(rule.Right);

if (left == null || right == null)
return null;

if (IsInteger(left) && IsInteger(right))
return Convert.ToInt64(left) * Convert.ToInt64(right);
else
return Convert.ToDecimal(left) * Convert.ToDecimal(right);
}

protected bool IsInteger(object o)
{
if (o is Int64)
return true;
if (o is Int32)
return true;
if (o is Int16)
return true;
return false;
}

I'm basically rounding up to the most accurate types Int64 or Decimal (I
should do double as well!)
Im still not sure if it works with all combinations. Before I was casting to
double for all types and it caused invalid casts from integers!

Tigger
 
In C++ maybe (since the operations are resolved at compile-time). But
in C#, generics rely on methods etc being resolved at compile time
*for any T*, since T is essentially a runtime argument (not
compile-time). Unfortunately, no methods suitable for generics are
defined for the numeric types.

Marc
 
Looch said:
Just a noob here, but isn't that what generics are for?

Unfortunately int, double, long, etc., don't implement a common
interface which dictates that the multiplier operator should be handled.
That means you can't come up with a constraint for it. By default object
* object doesn't work.

My bet is that even if you did this through reflection, it would still
be faster to use overloaded methods of every combination of base number
types you want to handle.

Chris.
 
Im this case it will be many, and I don't want to have to re workout all the
correct type conversions. e.g. int * double = double, float * decimal = ???

In the case of float*decimal, it wouldn't actually work in C#, as
neither is implicitly convertible to the other.

You could do this with autogenerated code and a dictionary from a pair
of types to a delegate, or from a dictionary of type to (a dictionary
of type to delegate). Call GetType() on each side, and then call the
delegate:

return multiplicationDelegates[left.GetType()][right.GetType()](left,
right);

The autogenerated code would have stuff like:

multiplicationDelegates[typeof(int)][typeof(float)] = delegate (object
left, object right) { return (int)left*(float)right };
multiplicationDelegates[typeof(int)][typeof(float)] = delegate (object
left, object right) { return (int)left*(double)right };

Not nice, and you'd need to make sure you excluded operations
involving both decimal and float/double, but it should work...

Jon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top