在应用程序中有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();
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?
答案 0 :(得分: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()
后,您可以可靠地访问FirstParts
和SecondParts
。
答案 1 :(得分:0)
您需要查看内部异常。 TypeInitializerException仅表示从构造函数内部抛出异常。异常将从对QuestionGenerator.GetNextQuestion()的调用中包含的代码生成;