2012-03-20 28 views
5

ジェネリック型を開くことができない理由をパラメータとして渡します。私はよく次のようなクラスを持っています:c#ジェネリック型をパラメータとして渡すことができないのはなぜですか?

public class Example<T> where T: BaseClass 
{ 
    public int a {get; set;} 
    public List<T> mylist {get; set;} 
} 

そう言いますと、BaseClassは以下のようになります。

public BaseClass 
{ 
    public int num; 
} 

私はその後、発言の方法をしたい:

public int MyArbitarySumMethod(Example example)//This won't compile Example not closed 
{ 
    int sum = 0; 
    foreach(BaseClass i in example.myList)//myList being infered as an IEnumerable 
     sum += i.num; 
    sum = sum * example.a; 
    return sum; 
} 

私は、次のように単にパラメータとして、この1つのクラスを渡すためのインタフェースを記述する必要があります。

public interface IExample 
{ 
public int a {get; set;} 
public IEnumerable<BaseClass> myIEnum {get;} 
} 

ジェネリッククラスを次に変更する必要があります:

public class Example<T>: IExample where T: BaseClass 
{ 
    public int a {get; set;} 
    public List<T> mylist {get; set;} 
    public IEnumerable<BaseClass> myIEnum {get {return myList;} } 
} 

コンパイラが推論できると思っていたことは、大いに盛大です。何かが変更できない場合でも、シンタックスのショートカットがない理由/正当性を知っていれば、心理的に非常に役立ちます。

+3

あなたがどのように制限をかけようとしているかわからないので、あなたが話している制限は本当に明確ではありません。私はあなたが何を意味しているのか考えていますが、その質問ははっきりしていません。 –

+0

"[どのように]ジェネリックタイプを開くか"と尋ねるとどういう意味ですか? –

+0

@Rich、 'T'が指定されていない場合、どうすれば構文的に' Example 'を(たとえ原則として)渡すでしょうか? –

答えて

2

私は似たような状況に陥っていますが、これは(非常に良い!)質問はありませんでした。

void F(Example<> e) { 
    Console.WriteLine(e.a); //could work 
} 

うん、これは理論的に仕事ができるが、これはしません:あなたが動作するように、次の期待

:今、私はそれについて考えることを余儀なくしていますことを、ここに私の答えである

void F(Example<> e) { 
    Console.WriteLine(e.mylist); //?? type unknown 
} 

コンパイラとCLRはメソッド本体とprooveを解析でき、最初のケースでは安全でないアクセスは実際には不可能であることを期待しています。そのとすることができます。それはなぜですか?おそらく、そのデザインは本当に健全で紛らわしいものではないでしょう。また、「デフォルトではすべての機能が実装されていません。誰かが実装、テスト、文書化する必要があります。

編集:この機能はCLRの協力なしには実装できないことを指摘します。 C#コンパイラは、オープンジェネリック型では不可能な、正確なメソッド呼び出しを行う必要があります。型システムでは、このような変数を現在許可していません。

+1

実際、すべての機能はデフォルトでは実装されていませんが、ジェネリックをたくさん使用しています。繰り返し同じパターンを繰り返し入力しています。私は他の人がこの機能の強い必要性を感じていないことに驚いています。型を閉じることは、本質的に継承の一種です。 –

+0

私の経験から、これは時々起こりますが、めったに起こらないことがわかります。確かに、これは完全にプロジェクトに依存します。しかし、私の主なポイントは本当にこの機能はおそらく混乱しているということです(「なぜmylistにアクセスできないのですか?」「なぜこれは機能するのですか?」)。絶対にすべての場合。 – usr

+0

おそらく私は典型的なC#コードを書いていないでしょう。私は夜の暗い時間に告白する必要があります、思考SmalltalkとLispは私の心を越えました。 –

2

実装の根拠:これをサポートするには、非公開のジェネリッククラスのメソッドをすべて仮想化する必要があります。そうでないと、特定のメソッドが「オープン」ジェネリック型を呼び出す方法がないことがあります。異なる閉鎖型メソッドの異なるジッタがあり、それぞれ対応するメソッドポインタがあります。インタフェースを手動で定義することは、どのメソッドを仮想として扱わなければならないかをコンパイラに指示することに対応し、公開する「公開」機能のサブセットを正確に指定することもできます。あなたが提案しているのは基本的に、すべてのジェネリッククラスにはパブリックインターフェイスの「公開」部分に対して暗黙的に生成されたインターフェイスクラスがあり、この機能が使用されなくてもクラスにパフォーマンスの影響があることです。

+0

実際、状況はそれより悪いです。 'Foo 'には、例えば、 「Foo .Bar」、「Foo .Bar」、「Foo .Bar」、「Foo .Bar」などの静的フィールド「バー」は、すべて異なる格納場所を参照する。異なる値を持つ可能性があります。それらのうちのどれに 'Foo <>。Bar 'が参照されていますか? 'Foo 'のいくつかのメンバーを呼び出すコンパイラが、そのメンバーが 'Foo .Bar'に直接的または間接的にアクセスできるかどうかを知ることができる一般的な方法はないので、呼び出す試みがあるかどうかを知る方法がありませんパラメータを持たない 'Foo <>'はおそらく安全です。 – supercat

1

たぶん私はあなたの正確な質問を理解していないんだけど、あなたはあなたの「MyArbitrarySumMethod」はこのようにそれを宣言することで、任意の例を取ることができます:

public int MyArbitarySumMethod<T>(Example<T> example) where T : BaseClass 

あなたはその後、「T」を指定せずにそれを呼び出すことができます。

int sum = MyArbitrarySumMethod(myExampleInstance); 

これはあなたが探しているものですか?

+0

@KirkWoll:いいえ、私はそうは思わない。このアプローチはまさに私が提案しようとしていたものです。 –

+0

@ジョン、あなたが正しいと思います。私はOPが一般的な型を渡す一般的な方法を探していたようでした.Tを参照せずに一般的な解決方法は*そのためのインタフェースラッパーを書くことです*。しかし、メソッドの特定のユースケースについては、これがうまくいくことは間違いありません。 –

関連する問題