2

在应用程序中有 2 个页面,CompletePoll.aspx、Default.aspx。

CompletePoll.aspx --> Page_Load()

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

完成投票()

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

问题生成器

          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 异常。如果我先访问 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一次,保存结果,并且永远不会再次尝试读取它。第一次成功时,never check again 可以是正确的,但第一次将要求HttpContext.Currentnot 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()被调用之后,您就可以FirstParts可靠地访问SecondParts

于 2012-11-26T09:36:52.887 回答
0

您需要查看内部异常。TypeInitializerException 仅表示从构造函数内部引发了异常。异常将从对 QuestionGenerator.GetNextQuestion() 的调用中包含的代码生成;

于 2012-11-26T09:19:47.837 回答