views:

358

answers:

2

I have two objects that can be represented as an int, float, bool, or string. I need to perform an addition on these two objects with the results being the same thing c# would produce as a result. For instance 1+"Foo" would equal the string "1Foo", 2+2.5 would equal the float 5.5, and 3+3 would equal the int 6 . Currently I am using the code below but it seems like incredible overkill. Can anyone simplify or point me to some way to do this efficiently?

private object Combine(object o, object o1) {
    float left = 0;
    float right = 0;

    bool isInt = false;

    string l = null;
    string r = null;
    if (o is int) {
        left = (int)o;
        isInt = true;
    }
    else if (o is float) {
        left = (float)o;
    }
    else if (o is bool) {
        l = o.ToString();
    }
    else {
        l = (string)o;
    }

    if (o1 is int) {
        right = (int)o1;
    }
    else if (o is float) {
        right = (float)o1;
        isInt = false;
    }
    else if (o1 is bool) {
        r = o1.ToString();
        isInt = false;
    }
    else {
        r = (string)o1;
        isInt = false;
    }

    object rr;

    if (l == null) {
        if (r == null) {
            rr = left + right;
        }
        else {
            rr = left + r;
        }
    }
    else {
        if (r == null) {
            rr = l + right;
        }
        else {
            rr = l + r;
        }
    }

    if (isInt) {
        return Convert.ToInt32(rr);
    }

    return rr;
}
+7  A: 

Can you use .NET 4.0? If so, it becomes very simple using dynamic typing:

private object Combine(dynamic o, dynamic o1)
{
    // Assumes an appropriate addition operator, found at execution time
    return o + o1;
}

Another alternative is to have a map of delegates for each pair of possible types. It's unfortunate that before .NET 4.0 there's no Tuple type, so you'll have to define your own TypePair type as the map key. Of course you then need to make sure you cover every possible pair... but at least the compiler can help when you've got a suitable "AddDelegate" method:

private void AddDelegate<T1, T2>(Func<T1, T2, object> sumFunction)
{
    // Put the function in the map
    ...
}

AddDelegate<int,int>((x, y) => x + y);
AddDelegate<int,float>((x, y) => x + y);
AddDelegate<int,string>((x, y) => x + y);
AddDelegate<float,int>((x, y) => x + y);
AddDelegate<float,float>((x, y) => x + y);
AddDelegate<float,string>((x, y) => x + y);
...

Btw, I've taken bool out of that as "addition" between a bool and a float (for example) doesn't make any sense. You can decide how you'd want to combine them though.

As Mitch says though, I'd revisit your design decisions - are you sure you really need this? It's a pretty odd requirement. Can you tell us anything about the bigger picture? We may be able to suggest alternative approaches.

Jon Skeet
what does the feature mean?
Benny
@Benny: Which feature?
Jon Skeet
Jon, thanks for the answer. Long story short im writing an interpreter in c#. I dont have a ton of type information on my variables at runtime. I may have just enough to implement your delegate idea though!What kind of speed concerns would I be looking at with object + object? Same as dynamic + dynamic??
Dested
Please tell me that `object o, object o2` is a typo... You mean `dynamic,` right? They aren't really going to just change the meaning of the plus operator for who knows how many applications in the wild... are they? ...are they? ...are they?!?!
Haha, Max that was my worry too. He seems to have edited it.
Dested
@Jon Skeet, understand now, the dynamic keyword works.
Benny
@MaxGuernseylll: Yes, it was a typo. Oops :) And no, C# 4 is still statically typed unless you've got a dynamic expression involved.
Jon Skeet
Jon, this is incredibly off subject but would dynamic c=0;c++;compile and run the way expected? That is do all operator methods run as expected when using dynamic?
Dested
@Dested: Not everything works *quite* as expected, although that example would. Example of where something would be off: `dynamic d = (byte) 0; byte b = 1; d += b; Console.WriteLine(d.GetType());` That *used* to print `System.Byte`, following the exact rules of C#'s compound assignment operators; it now prints `System.Int32`. I doubt that'll actually cause many people problems though :)
Jon Skeet
+4  A: 

You could just overload the method with the different types you want to use. It’s type-safe and simple.

    private string Combine(string o1, string o2) { return o1 + o2; }
    private string Combine(string o1, int o2) { return o1 + o2; }
    private string Combine(string o1, float o2) { return o1 + o2; }
    private string Combine(float o1, string o2) { return o1 + o2; }
    private float Combine(float o1, int o2) { return o1 + o2; }
    private float Combine(float o1, float o2) { return o1 + o2; }
    private string Combine(int o1, string o2) { return o1 + o2; }
    private float Combine(int o1, float o2) { return o1 + o2; }
    private int Combine(int o1, int o2) { return o1 + o2; }
tames
Simple features are often overlooked.
pokrate
The trick is efficiently determining the type of the object. That was the problem, not how to add each datatype to eachother.
Dested
When using an overloaded method, you don't have to determine the datatype: Combine("one", 2), Combine(3f, "four"), etc., will each call the appropriate overload. Let the compiler do it for you.
tames
This is perfect. Exactly what I was looking for
Dested
One thing to mention about this... it's really there to restrict the object types to be combined, otherwise if you allowed any type, you could just take the two values and use the expression o1+o2 instead of calling any method. But, incompatible types would fail.
tames