web-dev-qa-db-ja.com

Resharperがこのコードで「string []からobject []への共変配列変換は書き込み操作で実行時例外を引き起こす可能性がある」と言うのはなぜですか?

このコード:

comboBoxMonth.Items.AddRange(UsageRptConstsAndUtils.months.ToArray());

public static List<String> months = new List<String>
{
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
};

「string []からobject []への共変配列変換は書き込み操作で実行時例外を引き起こす可能性がある」という苦情でR#curmudgeonのようになります。

実際、このコードは完全に機能します。コンボボックスには月の値が入力されます。 Resharperは何について話しているのですか、そしてその疑問を和らげるために私は何ができますか?

総称リストに不正なデータが含まれている可能性があるだけの場合は、心配する必要はありません。問題が発生した場合でも、問題を追跡するのは簡単です。

20
B. Clay Shannon

メソッド_comboBoxMonth.Items.AddRange_には、_object[]_パラメーターが必要です。 months.ToArray()は_string[]_です。 _string[]_から_object[]_へのキャストは有効ですが、メソッドが配列の要素を変更しようとすると、ランタイムエラーが発生します。この場合はそうではないので、警告を無視できます。

煩わしい場合は、ToArray<object>()を使用できます

_comboBoxMonth.Items.AddRange(UsageRptConstsAndUtils.months.ToArray<object>());
_

_object[]_を返し、キャストは必要ありません。

33
Jakub Lortz

問題を示す例:

void Main()
{
    Animal[] animals = new Girafee[2];
    animals[0] = new Zebra();
}

public class Animal { }
public class Girafee : Animal { }
public class Zebra : Animal { }

これにより、実行時にArrayTypeMismatchExceptionがスローされます。

R#は基本的に、string[]object[]に割り当てているという事実の問題の可能性を示唆しています。これは、コンパイラによって完全に許可されていますが、次の場合は実行時の例外が発生する可能性があります。同じ基本クラスを共有するオブジェクトは、すでに別の型を指している配列に割り当てられます(私の例のように、実際にはgirafee配列を指します)。配列の共分散は、ジェネリックスで得られるコンパイル時の安全性を提供しないという意味で壊れています。

Eric Lippertがこれについて C#の共変性と反変性、パート2:配列共分散 :で説明しています。

残念ながら、この特定の種類の共分散は壊れています。 Javaはそれを必要とし、CLR設計者はJavaのような言語をサポートできるようにしたかったため、CLRに追加されました。その後、CLRに含まれていたため、C#に追加しました。これは当時、決定はかなり物議を醸しており、私はそれについてあまり満足していませんが、今はそれについて私たちにできることは何もありません。

なぜこれが壊れているのですか?カメを動物の配列に入れることは常に合法でなければならないからです。言語とランタイムの配列共分散では、バッキングストアが実際にはキリンの配列である可能性があるため、動物の配列が亀を受け入れることができるとは保証できません。

16
Yuval Itzchakov