2009-11-10 2 views
4

Я пытаюсь написать метод сравнения для сравнения свойств в некоторых POCOs с использованием Reflection, чтобы убедиться, что они были сохранены в базе данных правильно. Например, предположим, что у меня есть этот ПОКО:Как преобразовать объект из Reflection в общую коллекцию?

public class NoahsArk 
{ 
    public string Owner { get; set; } 
    public ICollection<Animal> Animals { get; set; } 
} 

То, что я хочу сделать это:

[Test] 
public class Saves_Correctly_To_Database() 
{ 
    var noahsArk = new NoahsArk { // some setup code here }; 
    db.Save(noahsArk); 
    var dbNoahsArk = db.Get<NoahsArk>(noahsArk.Id); 

    Assert.That(Compare(noahsArk, dbNoahsArk), Is.True); 
} 

ORM так я использую NHibernate. Мой метод сравнения выглядит следующим образом до сих пор:

public static bool EqualsProperties<T>(this T x, T y) 
{ 
    var xType = x.GetType(); 

    foreach (var property in xType.GetProperties()) 
    { 
     if (property.GetValue(x, null).Implements(typeof(ICollection<>))) 
     { 
      var xValue = property.GetValue(x, null) as ICollection<T>; 
      var yValue = property.GetValue(y, null) as ICollection<T>; 
     } 

Object.Implements() является метод расширения я написал, чтобы определить, если тип реализует интерфейс. Как видите, метод неполный. Проблема, с которой я сталкиваюсь, заключается в том, что, когда я использую property.GetValue(x, null), он возвращает object, и я не знаю, как отличить его в свой общий тип ICollection. Мне нужно сделать это, чтобы я мог использовать LINQ, чтобы сделать x.Contains(y), чтобы сравнить две коллекции для равенства. Любая идея о том, как это сделать?

P.S. Я пробовал использовать Compare .NET Objects, но он дает мне исключение с ссылкой на null где-то глубоко в NHibernate. Он неправильно обрабатывает, как NHibernate проксирует ICollection для ленивой загрузки. Хуже того, NHibernate модифицирует POCO для поддержки ленивой загрузки, но все это делается во время выполнения. В исходном коде похоже, что вы просто работаете с обычным ICollection, но NHibernate меняет это на NHibernate.Collections.Generic.PersistentSet во время выполнения, и это то, что приводит к сбою компаратора.

ответ

2

Ваш вопрос немного запутан, потому что вам не нужен параметр типа T в объявлении вашего метода EqualsProperties. Вам просто нужно

public static bool EqualsProperties(this object x, object y) 

Затем вы идете, чтобы использовать один и тот же параметр T бросить свойства х и у в ICollection<T>; однако объекты в этих коллекциях, очевидно, могут иметь разные типы, чем x и y.

Теперь, чтобы ответить на ваш вопрос: вам не нужно указывать правильный тип общего типа, чтобы использовать метод LINQ Contains. Вы можете сделать что-то вроде этого:

xValue = property.GetValue(x, null); 
yValue = property.GetValue(y, null); 
if (typeof(IEnumerable).IsInstanceOf(x)) 
{ 
    IEnumerable<object> xEnumerable = (x as IEnumerable).Cast<object>(); 
    IEnumerable<object> yEnumerable = (y as IEnumerable).Cast<object>(); 
    // use any LINQ method you like now 
} 

Вы также должны убедиться, что вы используете перегруженную LINQ, которые принимают компаратор равенства, так как ваш домен объекты явно не переопределить метод Equals себя. В противном случае вы не будете писать этот код тестирования устройства, чтобы сравнить их.

+0

Спасибо за ваш ответ. Мое мышление по поводу использования параметра типа T в объявлении заключалось в том, что это служит неявной первой проверкой того, что вы должны передать два объекта одного типа, иначе компилятор скажет, что он не может неявно преобразовать один из них в тип Т. –

0

Sharp architecture framework использовать атрибут для свойств декора, который следует принимать в метод equals. См. Исходный код класса DomainSignatureAttribute и метод EntityWithTypedId<>.Equals.