5

メソッドには型パラメーターがあります。コンストラクターに型パラメーターがないのはなぜですか?

役立つ例がいくつかあると思います (あまり多くはありません)。私の現在の問題は次のとおりです。

internal class ClassA
{
   private readonly Delegate _delegate;

   public ClassA<T>(Func<T> func)
   {
     _delegate = func;
   }
}

Delegate私のクラスにはAで十分です。しかし、それをメソッド グループとして渡すには、パラメーターを として定義する必要がありますFunc<T>

4

5 に答える 5

2

おそらく、あまり役に立たないだろうという前提で、単にその機能を含めなかったのです。

コンストラクターに必要な場合は、おそらく型全体に必要です。しかし、そうでない場合でも、おそらく Object を使用できます。

それができない場合は... ええ、それを回避する方法はあまりないと思います。申し訳ありません。:\ リフレクションを使用することはできますが、もちろんそれはとてつもなく遅くなります... または、メソッドを動的に生成してトリックをプレイすることもできます。これは、ユースケースによっては価値があるかもしれませんが、遅くなる可能性もあります (少なくとも 1追加の間接呼び出し)。

于 2012-05-11T07:48:25.667 に答える
2

コンストラクターはクラスの一部であるため、型パラメーターはおそらく型全体に属します。

ジェネリック クラスのインスタンスを構築するときに使用する別の型パラメーターを選択できる場合は、実際には別の型のクラスを構築しています。C++ のテンプレート クラスと同じではないことはわかっていますが、概念は似ています。

特定の問題を解決するには、「テンプレート化された」ファクトリ メソッドを使用できます。

于 2012-05-11T07:48:37.003 に答える
2

C# の仕様を読んだ後では、実際には理にかなっていますが、混乱する可能性があります。

各クラスには関連付けられたインスタンス型があり、ジェネリック クラス宣言の場合、インスタンス型は、型宣言から構築された型を作成することによって形成されます。指定された各型引数は、対応する型パラメーターです。

class C<T>
{ 
}

C<T>は構築された型であり、インスタンス型は、型パラメーターを使用して型を構築するプロセスによって作成されます。

C<String> c = new C<String>();

コンパイラは構築された type を取得C<T>し、指定された型パラメーターを使用して のインスタンス型C<String>が作成されました。Generics はコンパイル時の構成要素にすぎず、すべてが実行時に閉じた構成された型の観点から実行されます。

それでは、あなたの質問をここでテストしてみましょう。

class C
{
    public C<T>() 
    {
    }
}

存在しない型を構築しようとしているため、これは不可能です。

C c = new C<String>();

implicitまたはとのexplicit間の変換は何ですか? なにもない。意味がありません。CC<String>

Cこの例では は非ジェネリック型であるため、インスタンス型はクラス宣言そのものです。では、どのようC<String>に構築すると思いますCか?

あなたがしたいことの適切な宣言はこれです。

internal class Class<T> 
{
    private readonly Delegate _delegate;

    public Class(Func<T> function) 
    {
        _delegate = function;
    }
}

ここでは、構築Class<T>された型があるため、コンパイラによって適切なインスタンス型を作成できます。

Func<String> function = new Func<String>(() => { return String.Empty; });
Class<String> c = new Class<String>(function);

質問で希望する方法でそれをやろうとした場合。

Func<String> function = new Func<String>(() => { return String.Empty; });
Class c = new Class<String>(function);

構築された型は になりますがClass<String>、これは type と同じではなく、どちらからもまたは変換Cはありません。これがコンパイラによって許可されている場合、不明で使用できない状態になります。implicitexplicitC

構築された型について知っておく必要があるのは、これです。

class C<T>
{
    public C<T>() 
    {
    }
}

ジェネリック コンストラクターを明示的に宣言することはできませんが、これは有効ですが、実行時に閉じた型コンストラクターとしてのみ有効です。

C<String> c = new C<String>();

コンパイル時に、次のコンストラクターが作成されます。

public C<String>() 
{
}

これが有効な理由です:

C<String> c = new C<String>(); // We just used the closed type constructor

あなたが望んでいたことが許されれば、このようなことが起こる可能性があります.

class C<T>
{
    public C<U>() 
    {
    }
}

// ???
C<String> c = new C<Int32>();

コンストラクトが許可された場合に発生する問題を確認できます。仕様はかなり長く、ジェネリック、型パラメーター、構築された型、閉じた型と開いた型、バインドされた型とバインドされていない型をカバーする多くのセクションがあります。

非常に混乱する可能性がありますが、これがコンパイラの規則で許可されていないことは良いことです。

于 2012-05-11T08:17:25.687 に答える
1

厳密に型指定された Func<T> の代わりにデリゲートを渡すことができます。コンパイル時に型を知ることはできませんが、 Func<T> を渡すときにも型を知ることはできません。必要な場合は、クラス全体をジェネリックにする必要があります。

class Program {
        static void Main(string[] args) {
            Func<int> i = () => 10;
            var a1 = new ClassA(i);

            Func<string> s = () => "Hi there";
            var a2 = new ClassA(s);            
        }
    }

    internal class ClassA {
        private readonly Delegate _delegate;

        public ClassA(Delegate func) { // just pass in a delegate instead of Func<T>
            _delegate = func;
        }
    }
于 2012-05-11T08:14:13.433 に答える
0

クラスをジェネリックとして宣言することでそれを達成できるからです

internal class ClassA<T>
{
 private readonly Delegate _delegate;

  public ClassA(Func<T> func)
  {
    _delegate = func;
  }
}

次に、暗黙的にジェネリック構造を持ちます

于 2012-05-11T08:08:57.767 に答える