В момента съм в процес на добавяне на CodeContracts към моята съществуваща кодова база.
Едно нещо, което се оказва трудно, е използването на обекти, които са хидратирани от NHibernate.
Да приемем този прост клас:
public class Post
{
private Blog _blog;
[Obsolete("Required by NHibernate")]
protected Post() { }
public Post(Blog blog)
{
Contract.Requires(blog != null);
_blog = blog;
}
public Blog Blog
{
get
{
Contract.Ensures(Contract.Result<Blog>() != null);
return _blog;
}
set
{
Contract.Requires(value != null);
_blog = value;
}
}
[ContractInvariantMethod]
private void Invariants()
{
Contract.Invariant(_blog != null);
}
}
Този клас се опитва да защити инварианта _blog != null
. В момента обаче не успява, защото лесно бих могъл да създам екземпляр на Post
, като извлека от него и използвам защитения конструктор. В този случай _blog
ще бъде null
.
Опитвам се да променя кодовата си база по начин, който инвариантите наистина да са защитени.
Защитеният конструктор на пръв поглед е необходим на NHibernate, за да може да създава нови екземпляри, но има начин за заобикаляне на това изискване.
Този подход основно използва FormatterServices.GetUninitializedObject
. Важното е, че този метод не изпълнява никакви конструктори.
Мога да използвам този подход и това ще ми позволи да се отърва от защитения конструктор. Статичната проверка на CodeContracts сега ще бъде щастлива и няма да докладва повече нарушения, но веднага щом NHibernate се опита да хидратира такива обекти, той ще генерира изключения „invariant failed“, защото се опитва да зададе едно свойство след друго и всеки инструмент за настройка на свойства се изпълнява код, който проверява инвариантите.
Така че, за да направя всичко това да работи, ще трябва да се уверя, че обектите са създадени чрез техния публичен конструктор.
Но как да направя това?