在C#中合并两个对象的最有效方法

4
我有两个对象,可以表示为int、float、bool或string。我需要对这两个对象执行加法运算,结果应该与c#产生的结果相同。例如,1+“Foo”将等于字符串“1Foo”,2+2.5将等于浮点数5.5,3+3将等于整数6。目前我正在使用下面的代码,但似乎非常复杂。是否有简化的方法或指导我如何高效地完成这个任务?
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;
}

我会看一下你的设计... - Mitch Wheat
2个回答

8

您是否可以使用.NET 4.0?如果是,那么使用动态类型就变得非常简单:

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

另一种选择是为每对可能类型创建一个委托映射表。遗憾的是,在.NET 4.0之前没有Tuple类型,因此您需要定义自己的TypePair类型作为映射键。当然,您需要确保涵盖每个可能的对...但至少编译器可以在您有适当的“AddDelegate”方法时提供帮助:

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);
...

顺便提一下,我已经将“bool”从中拿出来了,因为在一个“bool”和一个“float”之间进行“addition”(例如)是没有意义的。但你可以决定如何组合它们。
正如Mitch所说,我建议重新审视你的设计决策 - 你确定你真的需要这个吗?这是一个相当奇怪的需求。你能告诉我们更多关于大局的信息吗?我们可能能够提出替代方案。

Jon,感谢你的回答。简而言之,我正在用C#编写一个解释器。在运行时,我的变量没有太多类型信息。不过,我可能有足够的信息来实现你的委托想法!使用object + object会有什么速度问题?与dynamic + dynamic相同吗? - Dested
请告诉我 object o, object o2 是打错了吧...你是指 dynamic,对吧?他们不会真的改变加号运算符的含义,影响到无数应用程序...是吗?难道他们会吗?他们会吗?他们会吗?! - MaxGuernseyIII
@MaxGuernseylll:是的,那是个打错字。糟糕 :) 不过,除非你使用了动态表达式,否则C# 4仍然是静态类型的。 - Jon Skeet
Jon,这个问题完全跑题了,但是使用动态语言编写以下代码:dynamic c = 0; c++;能够按照预期运行吗?也就是说,在使用动态语言时,所有的操作方法都能够按预期运行吗? - Dested
1
@Dested:并不是所有的东西都能像预期的那样工作,尽管这个例子可以。下面是一个会出问题的例子:dynamic d = (byte) 0; byte b = 1; d += b; Console.WriteLine(d.GetType()); 这个例子遵循了 C# 复合赋值运算符的精确规则,以前它会输出 System.Byte,但现在它输出 System.Int32。虽然我怀疑这不会给很多人带来问题 :) - Jon Skeet

5

您可以使用不同的类型重载该方法。这是类型安全和简单的。

    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; }

简单的功能经常被忽视。 - pokrate
关键是高效地确定对象的类型。这就是问题所在,而不是如何将每种数据类型相加。 - Dested
使用重载方法时,您无需确定数据类型:Combine(“one”,2),Combine(3f,“four”)等将每个调用适当的重载。让编译器为您完成。 - tames
这太完美了。正是我想要的。 - Dested
关于这个问题需要提一下的是,它实际上是用来限制对象类型的组合的,否则如果允许任何类型,你可以直接取两个值并使用表达式o1+o2而不是调用任何方法。但是,不兼容的类型会失败。 - tames

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接