Theo this question nó phải được đảm bảo rằng các trường tĩnh mà tôi sử dụng được khởi tạo:NullReferenceException từ singleton tĩnh inline khởi
10.4.5.1 tĩnh lĩnh vực khởi:
Trường tĩnh initializers biến của một lớp tương ứng với a chuỗi các bài tập được thực hiện theo thứ tự văn bản trong mà chúng xuất hiện trong tuyên bố lớp học. Nếu một hàm dựng tĩnh (Phần 10.11) tồn tại trong lớp, việc thực thi trường tĩnh trình khởi tạo xảy ra ngay lập tức trước khi thực hiện hàm tạo tĩnh đó. Nếu không, bộ khởi tạo trường tĩnh được thực hiện tại thời gian thực hiện phụ thuộc trước khi sử dụng lần đầu tiên của trường tĩnh của lớp đó.
Tôi đã gặp phải trường hợp lạ khi điều này có vẻ không đúng. Tôi có hai lớp có sự phụ thuộc vòng tròn vào nhau và nơi một số NullReferenceException
được ném.
tôi đã có thể tạo lại vấn đề này trong sau mẫu đơn giản, có một cái nhìn:
public class SessionManager
{
//// static constructor doesn't matter
//static SessionManager()
//{
// _instance = new SessionManager();
//}
private static SessionManager _instance = new SessionManager();
public static SessionManager GetInstance()
{
return _instance;
}
public SessionManager()
{
Console.WriteLine($"{nameof(SessionManager)} constructor called");
this.RecoverState();
}
public bool RecoverState()
{
Console.WriteLine($"{nameof(RecoverState)} called");
List<SessionInfo> activeSessionsInDb = SessionManagerDatabase.GetInstance().LoadActiveSessionsFromDb();
// ...
return true;
}
public List<SessionInfo> GetAllActiveSessions()
{
Console.WriteLine($"{nameof(GetAllActiveSessions)} called");
return new List<SessionInfo>();
}
}
public class SessionManagerDatabase
{
//// static constructor doesn't matter
//static SessionManagerDatabase()
//{
// _instance = new SessionManagerDatabase();
//}
private static readonly SessionManagerDatabase _instance = new SessionManagerDatabase();
public static SessionManagerDatabase GetInstance()
{
return _instance;
}
public SessionManagerDatabase()
{
Console.WriteLine($"{nameof(SessionManagerDatabase)} constructor called");
Synchronize();
}
public void Synchronize()
{
Console.WriteLine($"{nameof(Synchronize)} called");
// NullReferenceException here
List<SessionInfo> memorySessions = SessionManager.GetInstance().GetAllActiveSessions();
//...
}
public List<SessionInfo> LoadActiveSessionsFromDb()
{
Console.WriteLine($"{nameof(LoadActiveSessionsFromDb)} called");
return new List<SessionInfo>();
}
}
public class SessionInfo
{
}
Vấn đề vẫn còn nếu bạn bỏ ghi chú các nhà thầu tĩnh như đề xuất trong question khác. Sử dụng mã này để có được một TypeInitializationException
với NullRefernceException
như InnerException
trong Synchronize
tại SessionManager.GetInstance().GetAllActiveSessions()
:
static void Main(string[] args)
{
try
{
var sessionManagerInstance = SessionManager.GetInstance();
}
catch (TypeInitializationException e)
{
Console.WriteLine(e);
throw;
}
}
Console:
SessionManager constructor called
RecoverState called
SessionManagerDatabase constructor called
Synchronize called
System.TypeInitializationException: Der Typeninitialisierer für "SessionManager" hat eine Ausnahme verursacht. ---> System.TypeInitializationException: Der Typeninitialisierer für "SessionManagerDatabase" hat eine Ausnahme verursacht. ---> System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
bei ConsoleApplication_CSharp.Program.SessionManagerDatabase.Synchronize() in ......
bei ConsoleApplication_CSharp.Program.SessionManagerDatabase..ctor() in ......
bei ConsoleApplication_CSharp.Program.SessionManagerDatabase..cctor() in ......
--- Ende der internen Ausnahmestapelüberwachung ---
bei ConsoleApplication_CSharp.Program.SessionManagerDatabase.GetInstance()
bei ConsoleApplication_CSharp.Program.SessionManager.RecoverState() in ......
bei ConsoleApplication_CSharp.Program.SessionManager..ctor() in .....
bei ConsoleApplication_CSharp.Program.SessionManager..cctor() in ......
--- Ende der internen Ausnahmestapelüberwachung ---
bei ConsoleApplication_CSharp.Program.SessionManager.GetInstance()
bei ConsoleApplication_CSharp.Program.Main(String[] args) in ......
Tôi hiểu rằng có một số loại phụ thuộc vòng tròn ở đây (trong mã gốc không rõ ràng như vậy), nhưng tôi vẫn không hiểu tại sao mã không khởi tạo được những người độc thân. Cách tiếp cận tốt nhất cho trường hợp sử dụng này ngoài việc tránh phụ thuộc vòng tròn là gì?
Thật kỳ lạ, tôi đã mong đợi sẽ thấy 'StackOverflowException'. Nó thường không phải là một ý tưởng tốt để làm bất cứ điều gì quá tinh vi trong quá trình xây dựng, đặc biệt là khi mỗi là một singleton và mỗi cuối cùng gọi khác trước khi hoặc đã hoàn thành hoàn thành khởi tạo. Có lẽ nhìn vào _ initialferred initialisation_? – MickyD
Nếu bạn nhìn này: 'private SessionManager _instance = new SessionManager()', nó có hai bước quan trọng. 1.- Khởi tạo ('SessionManager()') và 2 asignation ('_instance = obj'). nếu bạn cố gắng sử dụng '_instance' trước khi asignation (như bạn làm), nó là null. Và nó ném NPE của bạn. –