比较两个对象的通用方法

4

我知道这是一个天真的问题,而且在两年的经验后,我还是无法回答它。

简单来说,我需要创建一个通用方法,这个方法可以接受 int、double 和 float 类型的参数,并将它们进行比较,找到最大值:

object ComapreMethod(object obj1, object obj2)
{ 
    if(obj1 > obj2)
    {
        return obj1;
    }

    return obj2;
}

我希望能为 int、short、ushort、float、double 等数据类型调用此功能,但我不知道如何比较 obj1 和 obj2。我无法按照上述方式编写代码。虽然我知道这很幼稚,但我不知道该怎么做。


4
最好选择“泛型”。 - Rahul Singh
我不明白你的意思。 - Miral
可能是重复的[C#泛型:如何比较通用类型的值?](https://dev59.com/8Ww15IYBdhLWcg3wpNUB) - Bob.
1
如果数据类型不同,您想要做什么?例如,将它们全部转换为double然后进行比较是否可行?编写比较函数的通常方式是返回一个指示哪个更大或更小的值,而不是立即返回最大的值。请参见http://msdn.microsoft.com/en-us/library/System.IComparable(v=vs.110).aspx以了解我所说的内容的示例。 - Chris
使用 Expression.GreaterThan :) - dev hedgehog
如果您想比较两种不同类型,请检查我的答案。在这种情况下,这不是重复! - mybirthname
4个回答

8

好的,您可以使用泛型更改方法签名:

TType ComapreMethod<TType>(TType obj1, TType obj2) where TType : IComparable

把你的代码从 if(obj1>obj2) 改为 if (obj1.CompareTo(obj2) > 0)(别忘了处理 obj1 和 obj2 都为空的情况)。

这样做的话,你就能在方法中传递一些实现了 IComparable 接口的类的值,包括 int、double 和 float。


你会如何使用这个方法比较整数和十进制数? - mybirthname
1
我写了如何比较两种不同类型的方法。 - mybirthname
1
隐式转换意味着,如果您使用十进制和整数调用它,它将只是将整数转换为十进制,因此即使类型混合也可以正常工作(我必须承认这是我所需的方式,但可能是错误的)。 - Chris
1
是的,是的,我写了关于我的例子的东西,这很愚蠢... :) 可能我应该更准确些。 - mybirthname
1
我同意在这种情况下使用 Math.Max 是最好的选择。可能 OP 的情况更加复杂,所涉及的过程也更加复杂,因此其他答案对于这些情况是有帮助的。 :) - Chris
显示剩余8条评论

4

有一个内置的解决方案可以实现你想要的功能,Math.Max (MSDN文档):

var myMax = Math.Max(input1, input2);

这将适用于任何可以隐式转换为相同类型的不同类型的input1和input2。因此,您可以交替使用intfloatdouble,它将返回适当类型的适当值(例如,如果传递int和double,则将返回double)。
如果您想要,您也可以修改您的方法以接受doubles。
double CompareMethod(double obj1, double obj2) 
{
    if (obj1.CompareTo(obj2) > 0)
    {
        return obj1;
    }
    return obj2;
}

这里再次使用了隐式类型转换,将整数转换为浮点数等。这意味着您的返回类型始终为double,但如果您希望返回int,则可以创建重载,编译器应选择最佳选项。
个人建议您只使用内置的。

可能 Math.Max 是最好的答案。我完全忘记了! - mybirthname

1

我假设您需要比较两种不同类型。例如int和decimal。

    static void Main(string[] args)
    {
        decimal p = 15.5m;
        int q = 5;

        Console.WriteLine(CompareTo<int, decimal, decimal>(q, p));

    }

    public static T3 CompareTo<T1, T2, T3>(T1 value1, T2 value2) 
        where T3:IComparable
    {
        T3 p = ConvertTo<T3>(value1);
        T3 q = ConvertTo<T3>(value2);

        if(p.CompareTo(q) >= 0)
        {
            return p;
        }
        else
        {
            return q;
        }
    }

    public static T ConvertTo<T>(object value)
    {
        try
        {
            return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
        }
        catch(Exception ex)
        {
            return (T)(typeof(T).IsValueType ? Activator.CreateInstance(typeof(T)) : null);
        }

    }

T1 是你的第一个值类型,T2 是你要比较的第二个值类型,T3 将是你所期望的结果类型(十进制、双精度等)。


0

你可以使用反射来完成。我首先获取第一个类型,然后获取 CompareTo 方法并运行它:

void Main()
{
    float a = 2;
    float b = 1;
    ComapreMethod(a, b); // A > B

    short c = 0;
    short d = 3;
    ComapreMethod(c, d); // A < B

    int e = 1;
    int f = 1;
    ComapreMethod(e, f); // A == B
}

// you can change the return type as you wish
string ComapreMethod(object a, object b)
{ 
    var result = Convert.ToInt32(a.GetType().GetMethods().First(o => o.Name == "CompareTo").Invoke(a, new object[] { b }));

    if (result == 0)
        return "A == B";
    else if (result > 0)
        return "A > B";
    else if (result < 0)
        return "A < B";
    else
        return "I don't know...";
}

是的,他可以。但使用泛型不仅更简单,而且更快。 - rsenna

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