Reflection - сравнение объектов и значения по умолчанию

Я пытаюсь сравнить два сложных объекта в C# и создать словарь, содержащий различия между ними.

Если у меня есть такой класс:

public class Product
{
    public int Id {get; set;}
    public bool IsWhatever {get; set;}
    public string Something {get; set;}
    public int SomeOtherId {get; set;}
}

И один пример, таким образом:

var p = new Product
                    {
                        Id = 1,
                        IsWhatever = false,
                        Something = "Pony",
                        SomeOtherId = 5
                    };

и другой:

var newP = new Product
    {
        Id = 1,
        IsWhatever = true
    };

Чтобы получить разницу между ними, я делаю вещи, которые включают это:

var oldProps = p.GetType().GetProperties();
var newProps = newP.GetType().GetProperties();

// snip 
foreach(var newInfo in newProps)
{
    var oldVal = oldInfo.GetValue(oldVersion, null);
    var newVal = newInfo.GetValue(newVersion,null);
}

// snip - some ifs & thens & other stuff

и именно эта линия представляет интерес

var newVal = newInfo.GetValue(newVersion,null);

Используя приведенные выше примеры объектов, эта строка даст мне значение по умолчанию 0 для SomeOtherId (та же история для bools & DateTimes и whathaveyou).

То, что я ищу, это способ иметь newProps включать только свойства, которые явно указаны в объекте, поэтому в приведенном выше примере Id а также IsWhatever, Я играл с BindingFlags но безрезультатно.

Это возможно? Есть ли более чистый / лучший способ сделать это или инструмент, который поможет мне избежать неприятностей?

Благодарю.

3 ответа

Решение

Я решил проблему, не используя рефлексию (или, по крайней мере, не используя ее таким образом).

Более или менее похоже на это:

public class Comparable
{
    private IDictionary<string, object> _cache;

    public Comparable()
    {
        _cache = new Dictionary<string, object>();
    }

    public IDictionary<string, object> Cache { get { return _cache; } }

    protected void Add(string name, object val)
    {
        _cache.Add(name, val);
    }
}

И реализация продукта идет к этому:

public class Product : Comparable
{
    private int _id;
    private bool _isWhatever;
    private string _something;
    private int _someOtherId;

    public int Id {get { return _id; } set{ _id = value; Add("Id", value); } }
    public bool IsWhatever { get { return _isWhatever; } set{ _isWhatever = value; Add("IsWhatever ", value); } }
    public string Something {get { return _something; } set{ _something = value; Add("Something ", value); } }
    public int SomeOtherId {get { return _someOtherId; } set{ _someOtherId = value; Add("SomeOtherId", value); } }
}

И сравнение тогда довольно простое

var dic = new Dictionary<string, object>();

foreach(var obj in version1.Cache)
{
    foreach(var newObj in version2.Cache)
    {
        //snip -- do stuff to check equality
        dic.Add(....);
    }
}

Не сильно пачкает модель и прекрасно работает.

Там нет флага, чтобы сказать, если вы были явно установлены свойства. Что вы можете сделать, это объявить ваши свойства как обнуляемые типы и сравнить значение со значением NULL.

Если я вас правильно понимаю, это то, что Microsoft сделала с классами обтекания xml, сгенерированными утилитой xsd, где у вас был XIsSpecifiedили что-то в этом роде для каждого свойства X,

Так что это то, что вы можете сделать, а не public int ID{get;set;}Добавить приватного участника _id или как вы его называете, и булево свойство IDSpecified который будет установлен в true всякий раз, когда Idсеттер называется

Другие вопросы по тегам