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
сеттер называется