【问题标题】:Compare by values from unknown object types按未知对象类型的值进行比较
【发布时间】:2014-11-10 23:26:04
【问题描述】:

我想做this question 之类的事情,但它没有按我的预期工作。

我有一个对象属性及其类型的列表、一个未知对象以及一个我想从对象中忽略的默认值类型列表。

public void GetOnlyNonDefault(object oObject, IgnoreValues ignoreValues)
{
    //properties is set beforehand
    for (int i = 0; i < properties.Count; i++)
    {
        object originalValue = 
            oObject
                .GetType()
                .GetProperty(properties[i].Name)
                .GetValue(oObject, null);

        //retrieving the default value I want to ignore for this property
        object ignoreValue = ignoreValues.GetDefaultOf(properties[i]);

        //Problem here

        //This doesn't work
        if (originalValue == ignoreValue) { continue; }

        //This works for nearly everything BUT enums
        if (ValueType.Equals(originalValue, ignoreValue)) { continue; }
    }
}

我从here 读到枚举的默认值为零,这就是当类型为枚举时我从GetDefaultOf 返回的值。 如何按值对上述代码中的所有值类型(包括枚举)进行比较?

编辑:可能是相关的,但我在 oObject 类中使用的枚举没有任何值设置为 0,它们都从 1 开始。

public enum UserStatus 
{
    Regular = 1, Manager = 2, Director = 3, Admin = 4
}

Edit²:这是我正在尝试执行的代码的基本版本,给出了我遇到的结果:http://pastebin.com/rfJA9CGp

我无法真正更改枚举,因为这就是这段代码的重点,我不知道运行时的对象是什么,也不知道它的属性,但我想计算与定义的默认值不同的任何值(类 @ 987654328@ 包含所有值类型的默认值)。

当它是一个枚举时,我无法转换为 int,因为这样我会忽略代码中实际上定义了带有 0 的枚举的情况,所以我正在寻找任何方法来比较这些值.

【问题讨论】:

  • 当比较 Objects you need to use the .Equals` 而不是 == 尝试将这一行 if (originalValue == ignoreValue) 更改为此,看看它是否产生预期的结果 if (originalValue.Equals(ignoreValue){ continue;}
  • @DJKRAZE 给出相同的结果(错误)。这和Object.Equals() 一样不是吗? ValueType.Equals 应该是相同的,但适用于 ValueTypes(我认为 Enum 是)。
  • 附带说明,对象的属性(PropertyInfo)将始终相同,因此您可以在oObject.GetType().GetProperty()的循环之外设置一个值,而不是每次都使用反射。
  • “这不起作用”是什么意思?这是否意味着该行抛出异常?比较两个值,即使它们看起来相等,但它们不是吗?还有什么?
  • 如果您在给您带来麻烦的行上设置了断点,originalValueignoreValue 的值是多少,它们与您的预期有何不同?

标签: c# enums


【解决方案1】:

当运算符== 被赋予静态类型为object 的值时,它会进行原始引用比较。值类型在放入类型为 object 的变量时(以及从反射调用返回时)必须装箱,因此比较总是错误的,因为即使是相等的值也会装箱到两个不同的实例。

比较枚举的一种方法是将值拆箱为 int:

        object foo1 = Foo.A;
        object foo2 = Foo.A;
        Console.WriteLine(foo1 == foo2);              // False
        Console.WriteLine((int) foo1 == (int) foo2);  // True

当变量不包含可以拆箱为 int 的内容时,此代码将失败,因此需要格外小心。特别是,如果枚举的底层类型不是int(可能发生),也会导致运行时异常。所以一个替代方案是Enum.Equals,它支持不同底层类型的枚举:

        object foo = Foo.A;
        if (foo.GetType().IsEnum)
            Console.WriteLine(Enum.Equals(foo, your-default-value));

现在您已经展示了如何获取要比较的默认值,我明白了问题所在。您将 integer 0 传递给 Enum.Equals。该方法以 integer 永远不等于枚举值的方式编写。获取默认值并不是很明显:

        object foo = Foo.A;
        object defaultEnumValue = Activator.CreateInstance(foo.GetType()))

        Enum.Equals(foo, defaultEnumValue);

您可能已经注意到,这是相对晦涩难懂的。这是因为当您的代码涉及处理所有可能的类型时,C# 通常不是很好。类型应该在编译时确定,但是当您编写检查任意对象的代码时,这当然是不可能的。

【讨论】:

  • Enum.Equals 也出于某种原因为我返回 false,尽管我希望它可以像 ValueTypes 一样工作......你的结果不同吗?
  • @Danicco 我不知道你到底在做什么,但这里有一个显示“True”的完整示例:pastebin.com/dC78PQvK
  • 这是我正在尝试做的示例的基本版本。我认为这有助于我找出问题所在,但仍然没有解决方案:pastebin.com/rfJA9CGp
  • 成功了!我什至不需要检查底部的枚举,第一个 ValueType.Equals 返回 true,谢谢!
猜你喜欢
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多