13

IDbSet のカスタム モックを作成して、モックの問題を回避しようとしています。

カスタム モック:

public class DbSetMock : IDbSet<Tenant>
{
    /* hidden all other implemented methods/properties */

    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, Tenant
    {
        throw new NotImplementedException();
    }
}

create メソッドで、解決方法がわからないビルド エラーが発生します。

制約クラスと 'class' または 'struct' 制約の両方を指定することはできません

制約から単純に削除するclassと、別のビルド エラーが発生します (これもわかりません :( )。

メソッド「Tests.DAL.Tenants.DbSetMock.Create<TDerivedEntity>()」の型パラメーター「TDerivedEntity」の制約は、インターフェイス メソッド「System.Data.Entity.IDbSet<BusinessLayer. DAL.Tenants.Tenant>.Create<TDerivedEntity>()'. 代わりに、明示的なインターフェイスの実装を使用することを検討してください。

このクラスをうまく構築するのを手伝ってくれる人はいますか?

4

4 に答える 4

17

TDerived型パラメーターは に制約されているため、制約orTenantを追加することは冗長です。制約を取り除くだけです。classstructclass

更新: 不思議なことに、ここでコンパイラ エラー間に競合があるようです。一方を「修正」すると、絶望の無限ループでもう一方が得られます。幸いなことに、2 番目のエラーからも解決策が得られます。明示的なインターフェイスの実装を使用できます。

public class DbSetMock : IDbSet<Tenant>
{

    TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
    {
        throw new NotImplementedException();
    }

}

明示的なインターフェイス実装を使用せずにそのメソッドを実装する方法はないようですクラスのパブリック インターフェイスの一部として必要な場合は、インターフェイスの実装が転送する別のメソッドを作成することをお勧めします。

public class DbSetMock : IDbSet<Tenant>
{

    TDerivedEntity IDbSet<Tenant>.Create<TDerivedEntity>()
    {
        return Create<TDerivedEntity>();
    }

    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
    {
        throw new NotImplementedException();
    }

}
于 2013-01-19T19:36:41.243 に答える
3

classこのように、メソッド部分から削除してみてください。

public class DbSetMock : IDbSet<Tenant>
    {
        /* hidden all other implemented methods/properties */

        public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : Tenant
        {
            throw new NotImplementedException();
        }
    }

class, Tenant冗長コードです。

于 2013-01-19T19:36:51.823 に答える
2

現在、フレームワークには、子孫が値型である可能性のある継承可能なクラスが3つだけあります:Object、、、。これらの3つの型はすべてクラス型ですが、値型から派生した、または値型になり、派生していない型はクラス型になります。上記以外のタイプの場合、aまたは制約は冗長または矛盾します。偶然ではありませんが、C#では、上記のタイプに制約を直接指定することはできません。ValueTypeEnumValueTypeEnumObjectValueTypeclassstruct

一部の言語とフレームワークでは、一般的な設計哲学は、その一般的な形式に適用される動作が役に立たない特定の形式の表現がある場合、言語/フレームワークの設計者が禁止する理由がないというものです。そのような形。そのような哲学の下では、ジェネリック型を封印された型に制約することは完全に合法です(たとえば、問題の型が封印されていて、将来のバージョンがそうでないFnord)場合、そのようなことは無意味です、しかし、ジェネリック制約の通常の解釈をそのような状況に適用すると、合理的な動作が得られ、そのような制約が役立つ可能性がある状況がある可能性があるため(たとえば、開発中で現在封印されているクラスを使用するコードを書くが、最終リリースで封印されている場合とされていない場合、または特定のジェネリック形式を期待するReflectionベースのコードとインターフェイスするコードを記述している場合、哲学は、ジェネリック型を封印されたクラスに制約することは合法であるべきだと示唆します。

他のいくつかの言語やフレームワークでは、異なる哲学が当てはまります。プログラマーが、ある特定の形式の構造が一般的な形式を超える機能を提供することを期待しているが、そうではない場合、およびその特定の形式がそのような機能なしではあまり役に立たないように思われる場合、言語の実装者がプログラマーがその実際の意味を表現したい理由を理解していない場合、構造が明確に定義され、他の手段で表現できない正確な意味を持っていても、言語はそれを禁止する必要があります。

C#も.netも、ある型パラメーターを別の型パラメーターに制約することに問題がないという事実は、他のパラメーターが制約として受け入れられないタイプである場合でも、制限が言語によって人為的に課されていることを示唆しています。前述の哲学。残念なことに、私見です。たとえば、言うことができると役立つ状況がたくさんあるからです。

bool HasAnyFlags<T>(this T enum1, T enum2) where T:struct,System.Enum

.netはそのような構成を有効に許可し、C#がそのような制約を除外することを妨げる唯一の障害は、それらを許可しないように明示的にそのような制約を探すことですが、C#の設計者は、そのような構成を許可するのではなく禁止することにしました。 .netがそれらを解釈するように動作します(つまり、でHasAnyFlagsできないことを直接行うTことはできません。また、 asSystem.Enumを使用することは、通常、を使用するよりも速くはありませんが(場合によっては遅くなります)、いくつかの理由:TSystem.EnumSystem.EnumT

  1. このメソッドは、コンパイル時に、パラメーターが*同じ*列挙型でなければならないことを強制できます。
  2. このメソッドは、静的クラス `EnumEvaluator`を使用して、タイプ` Func`の静的デリゲートを生成およびキャッシュし、 `HasAnyFlags(T enum1、T enum2)`を` return EnumEvaluator.HasAnyFlags(enum1、enum2);`として実装できます。 。このような関数は、`Enum.HasFlag`の10倍以上の速度になる可能性があります。

それでも、そのような制約を指定することは有用かもしれませんが、C#でそれらを指定する唯一の方法は、C#ソースコードに制約として使用できるダミータイプを指定させ、コンパイルされたコードをユーティリティを介して実行することです。ダミー型へのすべての参照を、最初に使用したい型への参照に置き換えます。

于 2013-01-20T19:03:26.360 に答える
1

制約が次のことを示しています。

class, Tenant

冗長です。はand includesよりも制約されているためclass、削除するだけです。Tenantclassclass

于 2013-01-19T19:37:31.740 に答える