将属性值转换回原始类型以与反射进行比较

时间:2018-11-02 23:34:01

标签: c# reflection

我目前正在尝试使用反射与数据合同进行比较。

数据协定代表虚拟机的配置。它们都是相同的类类型。设置新配置时,我试图记录配置中的所有更改。但是,数据合同具有大量成员。手动执行该操作很繁琐,并且无法容纳以后添加的新数据成员。

我尝试使用反射来做到这一点。我设法获取了数据成员的值,但是根据实际类型,比较它们会有所不同。

正在比较的一些成员是:

  • IEnumerable<Subnets>

  • IEnumerable<IP Address>

  • X509Certificates

  • Enums

还有一些

我正在尝试找到一种将属性转换为实际类的方法,但是到目前为止,我发现的所有方法都无法正常工作。

这是到目前为止我所做的反思的一个例子。

ExampleClass firstExample = new ExampleClass("a", 1);
ExampleClass secondExample = new ExampleClass("a", 2);
List<string> exampleList = new List<string>()
{
    "a",
    "b"
};

firstExample.ValueThree = exampleList;
secondExample.ValueThree = exampleList;

firstExample.FourthValue = new List<string>()
{
    "c",
    "d"
};

secondExample.FourthValue = new List<string>()
{
    "c",
    "d"
};

Type exampleType = firstExample.GetType();

foreach (PropertyInfo item in exampleType.GetProperties())
{
    var firstExampleValue = item.GetValue(firstExample);
    var secondExampleValue = item.GetValue(secondExample);
    string propName = item.Name;

    bool areEqual = firstExampleValue.Equals(secondExampleValue);

    Console.WriteLine(propName);
    Console.WriteLine(string.Format("\nFirst Value : {0}\nSecond Value : {1}", firstExampleValue, secondExampleValue));
    Console.WriteLine(string.Format("Values are equal : {0}\n\n", areEqual));
}

是否有一种实用的方法可以将它们转换为数据协定定义的实际类?我调查了Convert.ChangeType,但发现这对于大部分成员都不起作用,因为他们不是IConvertable

谢谢

埃德温

1 个答案:

答案 0 :(得分:0)

这与获取基础类型无关。这就是所谓的“相等”。

在.NET中,每种类型都继承自object,因此也继承了Object.Equals()。但是对于引用类型Object.Equals()仅比较两个对象是否为完全相同的对象,而不是它们的内容是否相等。

例如,new List<string>() == new List<string>()将始终为false

这就是firstExample == secondExamplefirstExampleValue.Equals(secondExampleValue)始终为false的原因。

但是,类可以覆盖Equals方法。例如,String会覆盖Equals(),以便比较两者的内容。

在这种情况下,如果ExampleClass是您控制的类,则可以覆盖Equals并告诉它比较每个属性的内容(以及每个List的内容)决定他们是否相等。完成此操作后,您只需写firstExample == secondExample,它就是true

Object.Equals()的文档实际上有一个简单的示例:https://docs.microsoft.com/en-us/dotnet/api/system.object.equals

更新:强制转换为基础类型没有任何好处。即使将类型强制转换为object,当您进行比较时,它仍会使用基础类型的Equals。例如,这将导致true((object)"hello") == ((object)"hello"),因为它使用String.Equals而不是Object.Equals

因此,您真正的问题是知道类型是否已覆盖Equals。您可以像这样测试类型是否覆盖了Equals

var type = typeof(string);
var overriddenEquals = type.GetMember("Equals").First().DeclaringType != typeof(object);

但是对于那些没有覆盖equals的类型,这仍然无济于事。您如何比较它们?

执行此操作的唯一方法是知道将使用的类型并针对这些类型进行测试(一堆if语句),并决定如何比较它们。 (对于列表,您可以测试is IEnumerable,循环遍历,然后测试列表中的类型)

在这种情况下,类型是否实现IConvertible并不重要,因为您将知道类型是什么并且可以直接将其强制转换为它,例如:

if (obj is Subnets objSubnets) {
    //compare objSubnets to another Subnets object
}