2

アプリケーションには、CompletePoll.aspx、Default.aspx の 2 つのページがあります。

CompletePoll.aspx --> Page_Load()

          Ultoo u = new Ultoo();
          u.UserName = Request["username"].ToString();
          u.Password = Request["password"].ToString();
          new Thread(u.CompletePoll).Start();

CompletePoll()

          .......
          .......
          String str = "Question:" + QuestionGenerator.GetNextQuestion(); /*Here i am getting Type initializer exception*/
          .......
          .......

QuestionGenerator

          public static class QuestionGenerator
          {
               private static string[] FirstParts = new StreamReader(HttpContext.Current.Server.MapPath("App_Data/QuestionPart1.txt")).ReadToEnd().Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
               private static string[] SecondParts = new StreamReader(HttpContext.Current.Server.MapPath("App_Data/QuestionPart2.txt")).ReadToEnd(). Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
               private static Random r = new Random();

               public static string GetNextQuestion()
               {
                    return FirstParts[r.Next(0, FirstParts.Length - 1)] + " " + SecondParts[r.Next(0, SecondParts.Length - 1)] + "?";
               }
          }

しかし、最初に Default.aspx を呼び出してから CompletePoll.aspx を呼び出すと、コードは正常に動作します。

Default.aspx --> Page_Load()

         Label1.Text = QuestionGenerator.GetNextQuestion();

したがって、ここで私の問題は、最初に CompletePoll.aspx にアクセスすると、TypeInitializer Exception が発生することです。最初に Default.aspx にアクセスしてから CompletePoll.aspx にアクセスしても、問題は発生しません。私のコードで何が問題なのですか。何か不足していますか? 最初に CompletePoll.aspx にアクセスするにはどうすればよいですか?

4

2 に答える 2

1
private static string[] FirstParts = new StreamReader(HttpContext.Current.Server.MapPath("App_Data/QuestionPart1.txt")).ReadToEnd().Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

それは正しくありません。これは、型が初期化されるときに一度チェックHttpContext.Currentし、結果を保存し、二度と読み取ろうとしません。最初に成功した場合は、二度とチェックしないことが正しい場合がありますが、最初はHttpContext.Currentそうではない必要がありますnull。最初の試行で例外が発生した場合、後で再初期化されることはありません。クラスがいつ初期化されるかを正確に確認できないためHttpContext.Current、その時点で が設定されているかどうかを確認できません (スレッドから呼び出した場合は設定されません)。

また、これは を呼び出さないStreamReader.Disposeため、ガベージ コレクタが実行されるまでリーダーとファイル自体を開いたままにします。

より安全な方法は次のようなものです

private static string[] firstParts; // field

private static string[] FirstParts // property
{
    get
    {
        if (firstParts == null)
        {
            using (var reader = new StreamReader(HttpContext.Current.Server.MapPath("App_Data/QuestionPart1.txt")))
                firstParts = reader.ReadToEnd().Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        }
        return firstParts;
    }
}

これにより、確実reader.Dispose()に呼び出され、型が初期化されたときではなく、プロパティが最初にアクセスされたときにファイルが読み取られるようになり、例外が実際に何が起こっているかをより簡単な方法で伝えることができます。FirstParts設定できない場合でも、残りのタイプは使用できます。

FirstPartsただし、スレッドから読み取らないことが必要です。スレッドを開始する前に一度読むことで、その問題を回避できます。

Ultoo u = new Ultoo();
u.UserName = Request["username"].ToString();
u.Password = Request["password"].ToString();
QuestionGenerator.Initialize(); // from the main thread
new Thread(u.CompletePoll).Start();


public static class QuestionGenerator
{
    public static void Initialize()
    {
        var firstParts = FirstParts;
        var secondParts = SecondParts;
        // merely reading the properties is enough to initialise them, so ignore the results
    }
}

スレッドが開始されたら、呼び出された後、確実Initialize()にアクセスできます。FirstPartsSecondParts

于 2012-11-26T09:36:52.887 に答える
0

内部例外を確認する必要があります。TypeInitializerException は、コンストラクター内から例外がスローされたことを意味します。例外は、QuestionGenerator.GetNextQuestion(); への呼び出しに含まれるコードから生成されます。

于 2012-11-26T09:19:47.837 に答える