C# で「int[] は uint[] == true」になるのはなぜですか
質問
誰かがC#を明確にしてくれませんか is
キーワードをお願いします。特に次の 2 つの質問:
Q1) 5行目;なぜこれが true を返すのでしょうか?
Q2) 7行目;なぜキャスト例外がないのでしょうか?
public void Test()
{
object intArray = new int[] { -100, -200 };
if (intArray is uint[]) //why does this return true?
{
uint[] uintArray = (uint[])intArray; //why no class cast exception?
for (int x = 0; x < uintArray.Length; x++)
{
Console.Out.WriteLine(uintArray[x]);
}
}
}
MSDN の説明では状況が明確になっていません。それは次のように述べています is
これらの条件のいずれかが満たされる場合に true を返します。(http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN 記事)
expression is not null. expression can be cast to type.
int[] を uint[] に有効にキャストできるとは思えません。なぜなら:
A) このコードはコンパイルできません:
int[] signed = new int[] { -100 };
uint[] unsigned = (uint[])signed;
B) デバッガでキャストを実行するとエラーが発生します。
(uint[])signed
"Cannot convert type 'int[]' to 'uint[]'"
案の定、3 行目が object ではなく int[] だった場合、コンパイルは行われません。それでは、Q2 に関連する最後の質問になります。
Q3) C# では、デバッガとコンパイラではキャスト/変換エラーが発生するのに、実行時には発生しないのはなぜですか?
解決
C#とCLRは多少異なる変換規則を有している。
C#でint[]
とuint[]
間することはできません。の直接のキャストの言語ので、は任意の変換が利用可能であると信じていません。あなたがobject
経由で行く場合は、結果はCLIまでです。 CLIの仕様のセクション8.7から、(私は願っています - 私は<のhref =「http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/2d21bf036a23918e#5a5c351206ebd999」引用していますエリックリッペルトは、しばらく前にをして、私はこのトピックに持っていたのrel =「noreferrer」>メール交換):
符号付きと符号なし整数プリミティブ タイプは、相互に割り当てることができます。 例えば、INT8:= uint8のは有効です。このため 目的、ブール値が考慮されなければなりません
uint8
およびその逆と互換性、 これbool := uint8
が有効になり、そして 逆に。また、これは当てはまります 署名された積分符号なしのアレイ 同じサイズのプリミティブ型。 例えば、int32[] := uint32[]
が有効である。
(私がチェックしていませんが、私は参照型変換が有効であることのこの種は、is
は同様にtrueを返しにするものであることを前提としています。)
これは、言語と基本的な実行エンジンとの間に切断があることは、やや残念だが、それは長期的にはかなり避けられないですが、私は疑います。そここのようないくつかの他の例がありますが、良いニュースは、彼らはめったに重大な害を引き起こすように見えるということです。
編集:マルクは彼の答えを削除したとして、私はC#のニュースグループに投稿されたとして、エリックからの完全なメールにリンクされてきました。
。他のヒント
それは興味深いですね。これは ECMA-335 標準で見つかりました。4.3 キャストクラス。ご了承ください:
配列は System.Array を継承します。
Foo を Bar にキャストできる場合は、Foo[] を Bar[] にキャストできます。
上記の注 2 の目的のため、列挙型はその基になる型として扱われます。したがって、E1 と E2 が基礎となる型を共有する場合、E1[] は E2[] にキャストできます。
int を uint にキャストすることはできますが、このように動作するのは非常に奇妙です。Visual Studio は、デバッガーが接続されているときは、時計も含めてこれらを認識せず、疑問符 '?' が表示されるだけです。
見てみるといいかもしれません これ, 、約 10 分早送りして、Anders が共変配列の実装について説明しているのを聞いてください。それがここでの根本的な根底にある問題だと思います。
提案ます:
というし、「intArrayオブジェクト」「INT [] intArray」としてintArray宣言すると、コンパイラは、無効なC#のキャストを拾うことができます。あなたは絶対にオブジェクトを使用する必要がない限り、私はそのアプローチを取るでしょう。
のRe Q2、Q3
は、実行時に、あなたは確認するでキャストをラップ試してみましたブロックする?
MSDNでこの記事から:
それが言うように、デフォルトでは、その式 唯一の定数値が含まれている原因 コンパイラエラーif式 外にある値を生成します 先の型の範囲。もし 式は、一つ以上が含まれています 非定数値は、コンパイラはありません オーバーフローを検出していない。
...
デフォルトでは、これらの非定数 式はチェックされません 実行時にオーバーフローのいずれか、そして彼ら オーバーフロー例外を発生させないでください。ザ・ 前の例を表示 2つの正の整数の和として-2147483639ます。
オーバーフローのチェックを有効にすることができ コンパイラオプション、環境 コンフィギュレーション、またはチェックの使用 キーワードます。
、あなたはコンパイラの設定や環境設定を経由して、よりグローバルチェックオーバーフローを強制することができます。
それはランタイムエラーが静かに発生しません署名数オーバーフローの可能性が無効な符号なしの数を確保することがスローされますよう、あなたのケースでは、これはおそらく望ましいます。
[更新]このコードをテストした後、私の代わりにINT []の型のオブジェクトの宣言を使用することにかかわらず有効になっているかどうかをチェックするのかを、標準的なC#の鋳造sytaxを迂回するように見えることを見出しました。
JSを使用すると、オブジェクトを使用する場合、あなたは、CLIの規則に縛ら、これらは明らかにこの問題が発生することを可能にしている、と述べている通ります。
Q1日時ます:
これは、上記に関連しています。キャストが、それは例外をスローしません関与ので、要するに、(現在のオーバーフローの設定に基づいて)。これは良いアイデアであるかどうかは別の問題である。
MSDN でから:
アン式が提供される発現が非nullの場合は、trueと評価され、「あります」 提供されたオブジェクトは、であることが例外を発生させることなく提供型にキャストすることができます スローます。
私は、.NET 1との下位compatablility推測しています。ちょうどCLR v1の中で、そのために考慮されていませんでした、そして今、それを維持しなければならないだろう「です」。
これは(uint[])(new int[]{})
ケースで働いていないことは、おそらくC#コンパイラ(ではないCLRランタイムが)厳しい型チェックを行うことができることによるものです。
また、アレイは単に一般的に安全でないタイプである
Animal[] tigers = new Tiger[10];
tigers[3] = new Elephant(); // ArrayTypeMismatchException
OK
私はこれで刺しを取るしようとします。
まず第一には、ドキュメントは言う、「オブジェクトが指定されたタイプと互換性があるかどうかをチェック。」、また、左側のタイプは「キャスト可能」である場合、上のタイプに(あなたは例外なく変換することができます)と言います式が非nullに評価し、右、そして、キーワードがtrue
して評価します「さ」。
他の回答のためにジョンスキートに目を向けます。彼はより雄弁に私ができるよりもそれを言いました。彼は変換が利用可能な場合、それはあなたが、その後、独自のを書くことができ、あなたの構文を受け付けますが、それはこのような状況ではやり過ぎと思われる、そうですねます。
参考: http://msdn.microsoft。 COM / EN-US /ライブラリ/ scekt9xw(VS.80).aspxのの