Привести значения свойств обратно к исходным типам для сравнения с отражением - PullRequest
0 голосов
/ 03 ноября 2018

В настоящее время я пытаюсь сравнить данные контрактов, используя отражение.

Контракт данных представляет собой конфигурацию для виртуальной машины. Они оба относятся к одному классу. Я пытаюсь регистрировать каждое изменение в конфигурации при установке новой конфигурации. Тем не менее, данные контракты имеют большое количество участников. Было бы довольно утомительно делать это вручную, и это не учитывает добавление новых элементов данных позже.

Я пытался использовать отражение, чтобы сделать это. Мне удалось получить значения членов данных, но в зависимости от фактического типа их сравнение будет различным.

Некоторые из сравниваемых членов:

  • 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.

Спасибо

Edwin

1 Ответ

0 голосов
/ 03 ноября 2018

Речь идет не о получении базового типа. Это примерно то, что считается "равным".

В .NET каждый тип наследуется от object и, следовательно, наследует Object.Equals(). Но для ссылочных типов Object.Equals() будет сравнивать только, являются ли два объекта точно таким же объектом , а не равны ли их содержания.

Например, new List<string>() == new List<string>() всегда будет false.

Вот почему firstExample == secondExample и firstExampleValue.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);

Но это все равно не поможет вам для типов, которые не переопределяют равно. Как вы их сравниваете?

Единственный способ сделать это - знать типы, которые будут использоваться, и тестировать их специально (набор if операторов) и решать, как вы будете их сравнивать. (для списков вы можете проверить на is IEnumerable, пройтись по нему, а затем проверить тип внутри списка)

И в этих случаях не имеет значения, реализует ли тип IConvertible, поскольку вы будете знать, что это за тип, и можете привести его непосредственно к нему, например:

if (obj is Subnets objSubnets) {
    //compare objSubnets to another Subnets object
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...