2009-03-04 18 views
6

最近、私はC#で非常に驚くべき動作を見出しました。 私はパラメータとしてIEnumerable<Object>を受け取り、私は IEnumerable<string>を渡すメソッドを持っていましたが、それはできません。 C#では、なぜこれができないのか、Objectにアップキャストできますか? それは私のために完全に混乱しています。 誰かがこの問題について私を明確にしてください。IEnumerable <Object>からIEnumerableへのキャスト<string>

+0

どのようにすることはできませんか?それは、ArgumentExceptionがを投げていますか?また、あなたがオブジェクトとしてそれを宣言するつもりならジェネリックのIEnumerableを使用してのポイントは何ですか? http://stackoverflow.com/questions/6557/in-c-why-cant-a-liststring-object-be-stored-in-a-listobject-variable –

+0

それは同じコンパイルエラー –

+0

です更新この古い答えは、共変性と反変性は現在、C#でサポートされており、これは現在有効なキャストです。 –

答えて

11

これの専門用語は、C#3.0以前ではジェネリックは不変であるということです。 C#4.0以降では、キャストが機能します。

不変の意味は、汎用タイプのパラメータが関連している(つまり、互いにサブタイプまたはスーパータイプである)という理由だけで、2つのジェネリックタイプ間には関係がないことを意味します。

この例では、文字列がオブジェクトのサブタイプであるため、IEnumerable<object>IEnumerable<string>の間にはタイピング関係はありません。文字列とintのような完全に無関係な2つの型とみなされています(これらはどちらもオブジェクトのサブタイプですが、すべてがあります)

実行したこの問題に対するいくつかの回避策と例外があります。

まず、個々の文字列を個別にオブジェクトにキャストできます。.NET 3.0を使用している場合は、Cast<T>()拡張メソッドを使用して行うことができます。それ以外の場合は、foreachを使用して、結果を必要な静的型の新しい変数に入れることができます。

第2に、配列は参照型の例外です。つまり、オブジェクト[]型を認識するメソッドに文字列[]型を渡します。型は機能します。

+1

だけに: –

0

あなたは

IEnumerable<T> 

を使用する必要がありますが、異なる種類に渡したい場合は、その後、あなたはそれの型を調べるためにTを照会することができます。

0

これについて考える良い方法は、「これを行うことができたらどうなりますか?」と自分自身に問いかけることです。次の例をご覧ください:

IEnumerable<String> strings=...; 
IEnumerable<Object> objects = strings; // assume this were legal 

objects.Add(new Integer(5)); // what the... 

文字列のリストに整数を追加しました。コンパイラは、型の安全性を保持するためにこれを行います。

+0

IEnumerable にはAddメソッドがありません.C#4.0では、宣言が(安全に)反変になるようにIEnumerable に変更されるため、実際にこのキャストを実行できます。 –

+0

さらに、ListのようなAddメソッドを持つジェネリッククラスを置き換えてください。 –

+0

-1: 'IEnumerable 'は.NET 4では 'IEnumerable 'になります。具体的には、あなたの引数はコンテナでは意味がありますが、列挙ではない* –

3

IEnumerable<object>を要する機能するIEnumerable<string>を通過する最も簡単な方法は、このような変換機能を介してである:

public IEnumerable<object> convert<T>(IEnumerable<T> enumerable) 
    { 
    foreach (T o in enumerable) 
     yield return o; 
    } 

C#4が出た場合、それは共変性と反変性をサポートするので、これは、neccessaryされません。

+2

これは><キャスト:) –

+0

のためのおかげで、まさにです!私はすでに、この、この提案の答えをupvoted。 –

8

他の人が指摘しているように、ジェネリック型は不変です。 IEnumerable<T>は共変種であることがありますが、C#は現在、変種の指定をサポートしていません。 C#4.0ではバリアントのサポートが予定されているため、将来サポートされる可能性があります。

これを回避するには、LINQ拡張方法Cast<object>()を使用できます。 Fooというメソッドがあり、それにはIEnumerable<object>>が必要だとします。

Foo(stringEnumerable.Cast<object>()); 
関連する問題