我正在尝试编写一个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。我尝试使用Compare .NET Objects,但它在NHibernate内部的某处给了我一个空引用异常。它没有正确处理NHibernate如何代表ICollection
进行延迟加载。更糟糕的是,NHibernate修改POCO以支持延迟加载,但这一切都是在运行时完成的。在源代码中,看起来您只是使用常规ICollection
,但NHibernate在运行时将此更改为NHibernate.Collections.Generic.PersistentSet
,这就是导致比较器失败的原因。
答案 0 :(得分:2)
您的问题有点令人困惑,因为您在EqualsProperties方法的声明中不需要类型参数T.你只需要
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方法本身。否则你不会编写这个单元测试代码来比较它们。
答案 1 :(得分:0)
Sharp architecture framework将属性用于装饰属性,这些属性应该用于equals方法。请参阅DomainSignatureAttribute
类和EntityWithTypedId<>.Equals
方法的源代码。