Как мне преобразовать объект из Reflection в общую коллекцию? - PullRequest
4 голосов
/ 11 ноября 2009

Я пытаюсь написать метод Compare для сравнения свойств в некоторых POCO, используя Reflection, чтобы убедиться, что они были правильно сохранены в базе данных. Например, скажем, у меня есть это POCO:

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. Я пытался использовать Сравнить объекты .NET , но это дает мне исключение нулевой ссылки где-то глубоко внутри NHibernate. Он не правильно обрабатывает, как NHibernate прокси ICollection для отложенной загрузки. Что еще хуже, NHibernate модифицирует POCO для поддержки отложенной загрузки, но все это делается во время выполнения. В исходном коде похоже, что вы просто работаете с обычным ICollection, но NHibernate меняет это значение на NHibernate.Collections.Generic.PersistentSet во время выполнения, и именно это приводит к сбою компаратора.

Ответы [ 2 ]

2 голосов
/ 11 ноября 2009

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

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

Затем вы продолжаете использовать тот же параметр T, чтобы привести свойства x и y к 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 голосов
/ 15 ноября 2009

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

...