System.InvalidTimeZoneException
タイム ゾーン情報が無効である場合にスローされる例外。
いくつかの発生パターンがあるようだが、今回はそのうちの2つを確認。
[実験ソース(C#)]
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// 10月の第2日曜日の4時に開始
TimeZoneInfo.TransitionTime s = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
new DateTime(1, 1, 1, 4, 0, 0), 10, 2, DayOfWeek.Sunday);
// 3月の第2日曜日の3時に終了
TimeZoneInfo.TransitionTime e = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
new DateTime(1, 1, 1, 3, 0, 0), 3, 2, DayOfWeek.Sunday);
// 1時間ずれる
TimeSpan delta = new TimeSpan(1, 0, 0);
// 2000年以降、s〜e の期間、1時間の夏時間を持つルールを作成
TimeZoneInfo.AdjustmentRule a = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
new DateTime(2000, 1, 1), DateTime.MaxValue.Date, delta, s, e);
TimeSpan offset = new TimeSpan(+14, 0, 0); // 夏時間の+1 とあわせて計14を超える
TimeZoneInfo.AdjustmentRule[] r = { a };
TimeZoneInfo.CreateCustomTimeZone("tzId", offset, "dispName", "stdName", "daylight", r);
}
}
}
[結果]
ハンドルされていない例外: System.InvalidTimeZoneException: BaseUtcOffset プロパティと DaylightDelta プロパティの合計はプラス マイナス 14.0 時間の範囲内である必要があります。
場所 System.TimeZoneInfo.ValidateTimeZoneInfo(String id, TimeSpan baseUtcOffset, AdjustmentRule[] adjustmentRules, Boolean& adjustmentRulesSupportDst)
場所 System.TimeZoneInfo..ctor(String id, TimeSpan baseUtcOffset, String displayName, String standardDisplayName, String daylightDisplayName, AdjustmentRule[] adjustmentRules, Boolean disableDaylightSavingTime)
場所 ConsoleApplication1.Program.Main(String[] args) 場所 Program.cs:行 22
[対処など]
世界協定時刻 (UTC: Coordinated Universal Time) オフセットと夏時間のデルタの合計が、±14時間の範囲内にないとこのエラーとなる。たとえば日本の場合、日本標準時(JST)は、+9時間なので、20行目の TimeSpan offset を +9に変えてやることで例外は発生しない。
もう1つ、複数ルール指定した場合のケースを実験してみる。
[実験ソース(C#)]
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// 10月の第2日曜日の4時に開始
TimeZoneInfo.TransitionTime s = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
new DateTime(1, 1, 1, 4, 0, 0), 10, 2, DayOfWeek.Sunday);
// 3月の第2日曜日の3時に終了
TimeZoneInfo.TransitionTime e = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
new DateTime(1, 1, 1, 3, 0, 0), 3, 2, DayOfWeek.Sunday);
// 1時間ずれる
TimeSpan delta = new TimeSpan(1, 0, 0);
// 2000年以降、s〜e の期間、1時間の夏時間を持つルールを作成
TimeZoneInfo.AdjustmentRule a = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
new DateTime(2000, 1, 1), DateTime.MaxValue.Date, delta, s, e);
// 2010年〜2020年の夏時間ルールを作成
TimeZoneInfo.AdjustmentRule b = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
new DateTime(2010, 1, 1), new DateTime(2020, 12, 31), delta, s, e);
TimeSpan offset = new TimeSpan(+9, 0, 0);
TimeZoneInfo.AdjustmentRule[] r = { a, b };
TimeZoneInfo.CreateCustomTimeZone("tzId", offset, "dispName", "stdName", "daylight", r);
}
}
}
[結果]
ハンドルされていない例外: System.InvalidTimeZoneException: AdjustmentRule 配列の要素は時系列である必要があり、重複することはできません。
場所 System.TimeZoneInfo.ValidateTimeZoneInfo(String id, TimeSpan baseUtcOffset, AdjustmentRule[] adjustmentRules, Boolean& adjustmentRulesSupportDst)
場所 System.TimeZoneInfo..ctor(String id, TimeSpan baseUtcOffset, String displayName, String standardDisplayName, String daylightDisplayName, AdjustmentRule[] adjustmentRules, Boolean disableDaylightSavingTime)
場所 ConsoleApplication1.Program.Main(String[] args) 場所 Program.cs:行 26
[対処など]
複数ルールを指定する場合は、期間が重複しないようにする。上記の例では、1つ目のルール(a)が2000年以降無限に適用される期間設定になっていることが原因。
System.InvalidProgramException
プログラムに無効な MSIL (Microsoft intermediate language) またはメタデータが含まれている場合にスローされる例外。通常、これはプログラムを生成したコンパイラのバグ、とのこと。
非常に興味をそそられたので調査してみたが、断念。KB312544の情報を元に、非常に長い命令文を生成してみた。
[実験ソース(C#)]
using System;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
const int COUNT = 1194; // 1193 まではOK
const string src = @"
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int a = 1;
int b = 0;
int c =
";
using (StreamWriter sw = new StreamWriter("Test.cs"))
{
sw.Write(src);
sw.Write(" ");
for (int i = 0; i < COUNT; i++)
{
sw.Write("(a == 1 ? ");
}
sw.WriteLine();
sw.Write(" ");
sw.WriteLine("a ");
sw.Write(" ");
for (int i = 0; i < COUNT; i++)
{
sw.Write(": b)");
}
sw.WriteLine(";");
sw.WriteLine(" }");
sw.WriteLine(" }");
sw.WriteLine("}");
}
}
}
}
[結果]
コンパイルするには、式が長すぎるか、または複雑すぎます。
(ビルド失敗)
[対処など]
長い三項演算子を作成してみたが、例外を発生させることはできなかった。コンパイルバグだと言っているくらいなので、改修されていて当たり前か・・・
System.InvalidOperationException
オブジェクトの現在の状態に対して無効なメソッド呼び出しが行われた場合にスローされる例外。
[実験ソース(C#)]
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<int> a = new List<int>();
a.Add(1);
foreach (int b in a)
{
a.Add(b);
}
}
}
}
[結果]
ハンドルされていない例外: System.InvalidOperationException: コレクションが変更されました。列挙操作は実行されない可能性があります。
場所 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
場所 System.Collections.Generic.List`1.Enumerator.MoveNextRare()
場所 System.Collections.Generic.List`1.Enumerator.MoveNext()
場所 ConsoleApplication1.Program.Main(String[] args) 場所 Program.cs:行 11
[対処など]
foreach でコレクションの列挙を開始した後で、コレクション自体を変更すると発生する。
どうしてもコレクションを変更する必要がある場合は、一旦別のコレクションにコピーしておき、列挙中にコレクションが変更されないようにしてやる。
System.InvalidCastException
無効なキャストまたは明示的な型変換に対してスローされる例外。
[実験ソース(C#)]
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//Char から Boolean、Single、Double、Decimal、または DateTime への変換。
Boolean a = Convert.ToBoolean('a');
//Boolean、Single、Double、Decimal、または DateTime から Char への変換。
Char b = Convert.ToChar(true);
//DateTime から String 以外の任意の型への変換。
int c = Convert.ToInt32(DateTime.Now);
//String 以外の任意の型から DateTime への変換。
DateTime d = Convert.ToDateTime(20100927);
}
}
}
[結果]
ハンドルされていない例外: System.InvalidCastException: 'Char' から 'Boolean' への無効なキャストです。
場所 System.Char.System.IConvertible.ToBoolean(IFormatProvider provider)
場所 ConsoleApplication1.Program.Main(String[] args) 場所 Program.cs:行 9
[対処など]
MSDN の Convert クラスに書かれていた4つの例を確認。この実験例は4つとも InvalidCastException が発生する。
ところが、InvalidCastException クラスに書かれていた例を試そうとしたが、OverflowException や InvalidOperationException が発生した。(解釈が間違っているのかも・・・)
試したプログラムは、次のとおり。
[実験ソース(C#)]
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//Single または Double から Decimal への変換で、変換元の値が無限、非数 (NaN)、または変換先の型で表現するには大きすぎる値の場合。
Decimal e = Convert.ToDecimal(Double.NaN); // OverflowException
Decimal f = Convert.ToDecimal(Double.PositiveInfinity); // OverflowException
Decimal g = Convert.ToDecimal(null); // エラーにならない
//明示的な参照変換の際にエラーが発生した場合。
Double? x = null;
Decimal h = (Decimal)x; // InvalidOperationException
}
}
}
System.InsufficientMemoryException
使用可能なメモリが十分に残っているかどうかのチェックで、要件が満たされなかった場合にスローされます。
[実験ソース(C#)]
using System;
using System.Runtime;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MemoryFailPoint mfp = new MemoryFailPoint(4 << 10); // MB単位(4GB)
}
}
}
[結果]
ハンドルされていない例外: System.InsufficientMemoryException: 操作の要求を満足させるメモリが不足しています。このシステムでは、この要求を満足させられない可能性があります。32 ビット システムの場合、3 GB モードで起動することを検討してください。
場所 System.Runtime.MemoryFailPoint..ctor(Int32 sizeInMegabytes)
場所 ConsoleApplication1.Program.Main(String[] args) 場所 Program.cs:行 9
[対処など]
実験したPCは、32ビットのVista。
十分なメモリが残っているか「チェック」する際に発生するとのことなので、MemoryFailPoint を使ってチェックを行ったところ発生。では、
byte[] a = new byte[int.MaxValue];
で発生するか、というと(予想どおり)発生しない。
System.StackOverflowException と System.InsufficientExecutionStackException
入れ子になったメソッド呼び出しが多くなりすぎ、実行スタックがオーバーフローした場合にスローされる例外。
[実験ソース(C#)]
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(f(decimal.MaxValue));
}
static decimal f(decimal n)
{
if (n <= 2) return 1;
return f(n - 1) + f(n - 2);
}
}
}
[結果]
Process is terminated due to StackOverflowException.
[対処など]
for文で書き直すなどすることで、再帰呼び出しを避ける。
本来は、System.InsufficientExecutionStackException (使用可能な実行スタックが不足していて、ほとんどのメソッドを実行できない場合にスローされる例外) を実験してみたくてフィボナッチ関数の単純再帰版を実行してみたところ、StackOverflowException の方が発生。
InsufficientExecutionStackException ってどうやったら発生するのだろう?
なお、StackOverflowException は .NET Framework 2.0 以降、try-catch によって補足できない例外となっている。
System.IndexOutOfRangeException
配列の境界外のインデックスを使用して配列の要素にアクセスしようとした場合にスローされる例外。
[実験ソース(C#)]
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] a = new int[3];
for (int i = 1; i <= a.Length; i++)
{
Console.WriteLine(a[i]);
}
}
}
}
[結果]
0
0ハンドルされていない例外: System.IndexOutOfRangeException: インデックスが配列の境界外です。
場所 ConsoleApplication1.Program.Main(String[] args) 場所 Program.cs:行 8
[対処など]
C# では、配列は 0オリジンなので、for (int i = 0; i < a.Length; i++) とする。
同じようでも、int[] 配列ではなく、List