質問

最近、c#で非常に驚くべき動作を発見しました。 パラメータとして IEnumerable< Object> をとるメソッドがあり、渡していました IEnumerable< string> しかし、それは不可能です。 C#では、これが不可能な理由よりもすべてをObjectにアップキャストできますか? それは私にとって完全に混乱しています。 この問題について誰かが私をクリアしてください。

役に立ちましたか?

解決

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

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

あなたの例では、 IEnumerable< object> IEnumerable< string> の間に型の関係はありません。これは、stringがオブジェクトのサブタイプだからです。これらは、文字列とintのように、まったく関係のない2つの型と見なされています(これらは両方ともオブジェクトのサブタイプですが、すべてがそうです)

この問題に遭遇したいくつかの回避策と例外があります。

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

次に、配列は参照型の例外です。つまり、string []型をobject []型を受け入れるメソッドに渡すことは機能します。

他のヒント

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

これを回避するには、LINQ拡張メソッド Cast< object>()を使用します。 IEnumerable< object>> を取る Foo というメソッドがあると仮定します。このように呼び出すことができます

Foo(stringEnumerable.Cast<object>());

IEnumerable&lt; string&gt; IEnumerable&lt; object&gt; を必要とする関数に渡す最も簡単な方法は、次のような関数を変換することです。

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

C#4がリリースされたとき、共分散と反分散をサポートするため、これは必要ありません。

使用する必要があります

IEnumerable<T> 

異なる型を渡したい場合は、Tを照会して、どの型かを調べることができます。

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

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top