2

C#のジェネリック制約を使用する際の特定の要件に不満があり、問題を回避する方法があるかどうかを知りたいです。そうでない場合は、物事が私が望むように機能しない理由について説明したいと思います。

この例は、私が現在基本的にしなければならないことを示しています。

public abstract class EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class LogicBase<TEntity, TID>
    where TEntity : EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class ServiceBase<TLogic, TEntity, TID>
    where TLogic : LogicBase<TEntity, TID>
    where TEntity : EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

// Concrete Examples
public class EgEntity : EntityBase<long> {}
public class EgLogic : LogicBase<EgEntity, long> {}
public class EgService : ServiceBase<EgLogic, EgEntity, long> {}

提案Aは、私が希望するものが利用可能であることを示しています(そして、それがこのように機能しなかった理由はわかりません):

public abstract class EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class LogicBase<TEntity>
    where TEntity : EntityBase<?>  // why not allow some kind of a "this could be whatever" syntax here ("?"), then infer the constraints on "?" based on the definition of EntityBase<>
{ }

public abstract class ServiceBase<TLogic>
    where TLogic : LogicBase<?>  // infer the constraints on "?" based on the definition of LogicBase<>
{ }

// Concrete Examples
public class EgEntity : EntityBase<long> {}
public class EgLogic : LogicBase<EgEntity> {}
public class EgService : ServiceBase<EgLogic> {}

提案Bは、提案Aほど魅力的ではありませんが、別の可能な代替案を示しています。

public abstract class EntityBase<TID>
    where TID : struct, IEquatable<TID>
{ }

public abstract class LogicBase<TEntity>
    where TEntity : EntityBase<TID>  // introduce TID here to keep it out of class signature
    where TID : struct, IEquatable<TID>
{ }

public abstract class ServiceBase<TLogic>
    where TLogic : LogicBase<TEntity>  // introduce TEntity here
    where TEntity : EntityBase<TID>  // introduce TID here
    where TID : struct, IEquatable<TID>
{ }

// Concrete Examples
public class EgEntity : EntityBase<long> {}
public class EgLogic : LogicBase<EgEntity> {}
public class EgService : ServiceBase<EgLogic> {}

どちらの提案も、派生型を作成するときに指定する必要のある型パラメーターの数を最小限に抑え、提案Aは、冗長な制約の束の必要性を排除します。

では、C#がこれらの提案の1つをサポートできなかった/提供できなかった理由はありますか?(または、偶然に、言語の関連する既存の機能を見落としたことがありますか?)

4

2 に答える 2

2

これがC#の基本的な方法です。タイプにどのような制限を課すことができるかという点で、どこにいくつかの制限があります。

一般的に言えば、where句のオプションのほとんどは、この制限を追加すると、使用されるジェネリック型に依存するジェネリッククラス内のオブジェクトで何かを実行できるようになるものに関連しています(例:それがでTIDあると言うことで、IEquatable<TID>TIDを使用できます後でIEquatableであるかのように)。ロジックは、その機能にまったく依存していない場合、クラスに制限が必要であるという事実上の理由はありません(ただし、クリーンさのためにそれが良い場合があることは認めます)。

希望するものになるLogicBase<?>と、このオブジェクトで今できることとまったく同じように、非常に複雑なパズルが提起されています。ServiceBase<TLogic>TLogicが定義され ている場合LogicBase<?>、LogicBaseのどの機能を実際に使用できますか?

ジェネリック型を知ることに依存しない機能のサブセットを取得しようとしている場合、私が言うことは、実際には、に依存しない機能を定義するか、Interfaceまたは単に定義する必要があるということです。データ型を指定し、この新しい型になるように制限します。それは現実的にあなたがあなたのために推論するようにアプリケーションに求めているものだからです(本質的にそのジェネリック型に依存しないのコンポーネントを表すインターフェース)。abstract classServiceBase<TLogic>TLogicServiceBase<TLogic>TLogicLogicBase<?>

したがって、理論的には、コンパイラはこれをこのように解釈し、データ型を参照せずにオブジェクトへの制約と使用可能なインターフェイスの望ましい強制を実行できますが、継承の設定と私の個人的な考えでは、インターフェイスを宣言するだけで、問題に対処するためのより構造化された方法になります。

于 2012-07-02T07:35:30.513 に答える
0

インターフェイス IEntityBase を定義して、LogicBase と ServiceBase をこのインターフェイスのみに依存させてみませんか。これにより、TEntity 型パラメーターを取り除くことができます。

于 2012-07-02T07:49:12.653 に答える