4

現在、CodeContracts を既存のコード ベースに追加する作業を行っています。
難しいことの 1 つは、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 がそのようなエンティティをハイドレートしようとするとすぐに、「不変の失敗」例外が生成されます。不変条件を検証するコード。

したがって、これらすべてを機能させるには、パブリック コンストラクターを介してエンティティをインスタンス化する必要があります。

しかし、どうすればこれを行うことができますか?

4

2 に答える 2

2

ダニエル、私が間違っていなければ (NH と一緒に仕事をしてからしばらく経ちます)、プライベート コンストラクターを使用できます。

それ以外に、なぜ100%確実である必要があるのでしょうか? それはなんらかの要件ですか、それともすべてのベースをカバーしようとしているだけですか?

要件によっては、それを達成するための別の方法が考えられるからです。

追加の保護を提供するために今できることは、 IInterceptor クラスを接続して、ロード後もクラスがまだ有効であることを確認することです。

肝心なのは、誰かがあなたのドメインとクラスを台無しにしたい場合、あなたが何をしても彼らはそれをするだろうということだと思います. ほとんどの場合、これらすべてを防止しようとする努力は報われません。

明確化後に編集

オブジェクトを使用してデータベースに書き込み、コントラクトが機能している場合、誰もデータベースを改ざんしなければ、データが正しく書き込まれ、したがって正しくロードされると安全に想定できます。

データベースを手動で変更する場合は、それをやめてドメインを使用してそれを行うか (検証ロジックがある場所)、データベースの変更プロセスをテストする必要があります。

それでも、本当に必要な場合は、ロード後にエンティティを検証する IInterceptor を接続できますが、家のパイプが正常であることを確認することで、通りから来る水浸しを修正するとは思いません。

于 2013-02-27T12:17:12.943 に答える