5

.NET Genericsの概念を理解し、実際に自分のコードで使用しようとしていますが、問題が発生し続けています。

次のセットアップがコンパイルされない理由を誰かが私に説明しようとすることができますか?

public class ClassA
{
    ClassB b = new ClassB();

    public void MethodA<T>(IRepo<T> repo) where T : ITypeEntity
    {
        b.MethodB(repo);
    }
}

public class ClassB
{
    IRepo<ITypeEntity> repo;

    public void MethodB(IRepo<ITypeEntity> repo)
    {
        this.repo = repo;
    }
}

次のエラーが発生します:
IRepo<'T>からIRepo<'ITypeEntity>に変換できません

MethodAは、DetailTypeがITypeEntityから継承するIRepo<'DetailType>オブジェクトパラメータで呼び出されます。

MethodA内のTをITypeEntityタイプに制限しているので、これはコンパイルする必要があると私は考え続けています。

どんな考えやフィードバックも非常に役に立ちます。

ありがとう。

編集:ニックRは素晴らしい提案をしていますが、残念ながら私の文脈では、ClassAをGenericにするオプションはありません。ClassBはそうかもしれません。

4

10 に答える 10

3

ジェネリックスを使用する場合、継承は同じようには機能しません。Smasheryが指摘しているように、TypeAがTypeBを継承していても、myType<TypeA>はmyType<TypeB>を継承しません。

そのため、myType <TypeB>を期待してMethodA(myType <TypeB> b)として定義されたメソッドを呼び出して、代わりにmyType<TypeA>を指定することはできません。問題のタイプは完全に一致する必要があります。したがって、以下はコンパイルされません。

myType<TypeA> a; // This should be a myType<TypeB>, even if it contains only TypeA's

public void MethodB(myType<TypeB> b){ /* do stuff */ }

public void Main()
{
  MethodB(a);
}

したがって、あなたの場合、DetailTypesのみが含まれている場合でも、IRepo<ITypeEntity>をMethodBに渡す必要があります。2つの間で変換を行う必要があります。一般的なIListを使用している場合は、次のようにすることができます。

public void MethodA<T>(IList<T> list) where T : ITypeEntity
{
  IList<T> myIList = new List<T>();

  foreach(T item in list)
  {
    myIList.Add(item);
  }

  b.MethodB(myIList);
}

これがお役に立てば幸いです。

于 2008-09-23T23:16:06.307 に答える
3

さて、これは問題なくコンパイルされます。私は基本的にクラスを再定義して、ジェネリック パラメーターを受け取りました。これはあなたのコンテキストでは問題ないかもしれません。

public interface IRepo<TRepo>
{
}

public interface ITypeEntity
{
}


public class ClassA<T> where T : ITypeEntity
{
    ClassB<T> b = new ClassB<T>();
    public void MethodA(IRepo<T> repo)
    {
        b.MethodB(repo);
    }
}
public class ClassB<T> where T : ITypeEntity
{
    IRepo<T> repo;
    public void MethodB(IRepo<T> repo)
    {
        this.repo = repo;
    }
}
于 2008-09-23T22:52:22.383 に答える
2

この問題は、理解するのが難しい問題です。DetailType は ITypeEntity から継承される場合がありますが、実際には ITypeEntity ではありません。DetailType の実装によって異なる機能が導入される可能性があるため、DetailType は ITypeEntity を実装しますが、ITypeEntity と等しくありません。それが理にかなっていることを願っています...

于 2008-09-23T22:46:27.733 に答える
1

次のエラーが表示されます: IRepo<'T> から IRepo<'ITypeEntity> に変換できません

と が同じではないIRepo<T>ため、このコンパイル エラーが発生しています。後者は前者の特殊化です。はジェネリック型定義であり、型パラメーター T はプレースホルダーであり、ジェネリック型定義の構築されたジェネリック型であり、型パラメーター T from は に指定されています。IRepo<ITypeEntity>IRepo<T>IRepo<ITypeEntity>ITypeEntity

MethodA 内の T を ITypeEntity 型に制限しているため、これはコンパイルする必要があると考え続けています。

このwhere制約は、 の呼び出しサイトで T に指定できる型を制約するだけなので、ここでは役に立ちませんMethodA

MSDN のドキュメント (「.NET Framework のジェネリック」を参照) にある用語が参考になる場合があります。

  • ジェネリック型定義は、テンプレートとして機能するクラス、構造体、またはインターフェイスの宣言であり、格納または使用できる型のプレースホルダーがあります。たとえば、Dictionary<<K, V>クラスにはキーと値の 2 つの型を含めることができます。これは単なるテンプレートであるため、ジェネリック型定義であるクラス、構造体、またはインターフェイスのインスタンスを作成することはできません。

  • ジェネリック型パラメーターまたは型パラメーターは、ジェネリック型またはメソッド定義のプレースホルダーです。Dictionary<K, V>ジェネリック型には、そのキーと値の型を表す 2 つの型パラメーター K と V があります。

  • 構築ジェネリック型または構築型は、ジェネリック型定義のジェネリック型パラメーターの型を指定した結果です。

  • ジェネリック型引数は、ジェネリック型パラメーターの代わりに使用される任意の型です。

  • ジェネリック型という一般的な用語には、構築された型とジェネリック型の定義の両方が含まれます。

  • 制約は、ジェネリック型パラメーターに課される制限です。たとえば、型パラメーターをIComparer<T>ジェネリック インターフェイスを実装する型に限定して、型のインスタンスを順序付けできるようにすることができます。型パラメーターを、特定の基本クラスを持つ型、既定のコンストラクターを持つ型、または参照型または値型である型に制約することもできます。ジェネリック型のユーザーは、制約を満たさない型引数を置き換えることはできません。

于 2008-09-23T22:53:00.417 に答える
1

@monoxideの質問をご覧ください

そして、私がそこで述べたように、ジェネリックの反変性と共変性に関する Eric Lippert の一連の投稿をチェックすると、この多くがより明確になります。

于 2008-09-23T22:54:19.947 に答える
0

ジェネリック メソッドに頭を悩ませている状況で、単純なジェネリック関数を紹介させてください。これは、VB の IIf() (Immediate if) に相当する一般的なものであり、それ自体が C スタイルの三項演算子 (?) のよくない模倣です。実際の三項演算子の方が優れているため、何の役にも立ちませんが、ジェネリック関数がどのように構築され、どのコンテキストで適用されるべきかを理解するのに役立つかもしれません。

T IIF<T>(bool Expression, T TruePart, T FalsePart)
{
    return Expression ? TruePart : FalsePart;
}
于 2008-09-23T23:59:58.150 に答える
0

Class<B>B が A のサブクラスである場合、それは のサブクラスであることを意味しませんClass<A>。したがって、これと同じ理由で、「が」であると言っても、「がTITypeEntityであるとは限りません。これを機能させたい場合は、独自の変換メソッドを作成する必要がある場合があります。IRepo<T>IRepo<ITypeEntity>

于 2008-09-23T22:47:04.037 に答える
0

T は、使用時に特定の型にバインドされる型変数です。この制限により、その型はITypeEntity を実装する型のサブセットを表し、インターフェイスを実装する他の型は除外されます。

于 2008-09-23T22:48:18.027 に答える
0

コンパイル時に、制約を付けていても、コンパイラは MethodA の T が参照型であることしか認識していません。どのタイプに制約されているかはわかりません。

于 2008-09-23T22:51:48.547 に答える
0

これは、ジェネリックの冗長な使用です。T が ITypeEntity のインスタンスにしかならない場合は、ジェネリックを使用しないでください。

ジェネリックは、何かの中に複数の型がある場合に使用します。

于 2008-09-23T22:52:32.103 に答える