c# - 盒装值类型比较

标签 c# reflection value-type boxing unboxing

我在这里试图实现的是盒装原始类型的直接值比较。

((object)12).Equals((object)12); // Type match will result in a value comparison,
((object)12).Equals((object)12d); // but a type mismatch will not. (false)
object.Equals((object)12,(object)12d); // Same here. (false)

我理解“为什么”。我只是看不到“如何”。

类型直到运行时都是未知的,它们可以是来自数据源的任何原始类型。这包括字符串、日期时间、 bool 值等。 我已经沿着丑陋的路线写了一个扩展方法来解决这两种类型,然后在进行“==”比较之前进行转换:(为了完整起见,我包括了每个原始类型,以及我感兴趣的那些)

public static bool ValueEquals(this object thisObj, object compare)
    {
        if (thisObj is int)
        {
            int obj = (int)thisObj;
            if (compare is int)
                return (obj == (int)compare);
            if (compare is uint)
                return (obj == (uint)compare);
            if (compare is decimal)
                return (obj == (decimal)compare);
            if (compare is float)
                return (obj == (float)compare);
            <... and so on for each primitive type ...>
        }
        if (thisObj is uint)
        {
            uint obj = (uint)thisObj;
            if (compare is int)
                return (obj == (int)compare);
            if (compare is uint)
                return (obj == (uint)compare);
            <... Again for each primitive type ...>
        }
        if (thisObj is decimal)
        {
            decimal obj = (decimal)thisObj;
            if (compare is int)
                return (obj == (int)compare);
            <... Etc, etc ...>

生成的方法原来有 300 多行,这很好(但很可怕),但现在我需要做的不仅仅是“==”。我需要 >、<、<=、>=、!=。

Reflection 中有什么可以用于盒装值类型比较吗?

有什么吗?

最佳答案

看起来您假设 arg1 中的类型是您要转换成的类型,所以我会使用这样的类属。只要 arg2 是 IConvertible(int、double、所有数字、字符串等都是 IConvertible),这将起作用:

public static bool ValueEquality<T1, T2>(T1 val1, T2 val2) 
    where T1 : IConvertible 
    where T2 : IConvertible
{
    // convert val2 to type of val1.
    T1 boxed2 = (T1) Convert.ChangeType(val2, typeof (T1));

    // compare now that same type.
    return val1.Equals(boxed2);
}

** 更新 ** 使这两种类型都成为通用 args,既可以推断又可以在 arg2 上添加更多编译时安全性,以确保它在编译时是 IConvertible。

给定这个通用函数,以下所有函数现在都返回 true(不需要指定类型参数,因为从第一个参数推断:

        Console.WriteLine(ValueEquality(1, "1"));
        Console.WriteLine(ValueEquality(2, 2.0));
        Console.WriteLine(ValueEquality(3, 3L));

更新

根据您的评论,如果您拥有的只是对象,那么这里会出现过载。两者可以共存,它会根据参数调用更合适的一个:

    public static bool ValueEquality(object val1, object val2)
    {
        if (!(val1 is IConvertible)) throw new ArgumentException("val1 must be IConvertible type");
        if (!(val2 is IConvertible)) throw new ArgumentException("val2 must be IConvertible type");

        // convert val2 to type of val1.
        var converted2 = Convert.ChangeType(val2, val1.GetType());

        // compare now that same type.
        return val1.Equals(converted2);
    }

这将适用于对象:

        object obj1 = 1;
        object obj2 = 1.0;

        Console.WriteLine(ValueEquality(obj1, obj2));

正如我所说,这两者都可以作为重载共存,因此如果您直接比较兼容的 IConvertible 类型,它将使用泛型,如果您只有装箱类型作为对象,它将使用对象重载。

关于c# - 盒装值类型比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6668697/

相关文章:

c# - 在 Xamarin 中获取 OutOfMemoryException

c# - Node.SelectNodes(/*) 和 Node.childNodes 有什么区别?

c# - SOS.dll ObjSize 和 DumpObject 背后的复杂之处。如何在 C# 中重新创建 SOS.dll?

java - 使用 Java 反射的包与 protected 保护

Java 8 关于实例创建的注释

c# - 对父线程中的变量评估感到困惑

C# WPF - ListView 项目到 TextBox

c# - 传递给迭代器的值类型的可变包装器

c# - 如何将 valuetype 设置为正整数?

.net - 可变结构有什么好的用途?