3 回答

TA貢獻(xiàn)1900條經(jīng)驗(yàn) 獲得超5個贊
請記住,TcpClient(string, int)
構(gòu)造函數(shù)會在此時打開一個新連接 ( doc ):
初始化 TcpClient 類的新實(shí)例并連接到指定主機(jī)上的指定端口。
...
此構(gòu)造函數(shù)創(chuàng)建一個新的 TcpClient 并嘗試對提供的主機(jī)名和端口號進(jìn)行同步連接。
如果我復(fù)制/粘貼您的代碼(插入我自己的RemoteServerIpAddressString
),那么我會看到應(yīng)用程序在嘗試構(gòu)建TcpClient
. 如果我在那時中斷調(diào)試器,我可以看到它卡在 中System.Net.Sockets.Socket.DoConnect
,它正在嘗試連接到遠(yuǎn)程機(jī)器。
一段時間后它放棄,拋出一個異常,然后拋出一個異常TypeInitializationException
,這會破壞調(diào)試器。
這符合您的觀察:
在創(chuàng)建 TcpClient 實(shí)例之后,幾乎沒有任何事情(或者更確切地說,沒有任何事情立即可見)發(fā)生——沒有拋出異常;該程序不會自行終止;控制臺保持空白。
此時,TcpClient
仍在嘗試連接。在它成功之前,該類型永遠(yuǎn)不會被初始化,并且在這發(fā)生Main
之前永遠(yuǎn)不會運(yùn)行。如果你離開它的時間足夠長,它可能會失敗,就像我的一樣。
如果我確定TcpClient
正在連接到一個打開的端口,那么TcpClient
構(gòu)造函數(shù)會立即完成并Main
運(yùn)行。
在靜態(tài)構(gòu)造函數(shù)中做長時間運(yùn)行的事情——尤其是與網(wǎng)絡(luò)有關(guān)的事情——是一個非常糟糕的主意。CLR 需要在初始化一個類型時獲取鎖,這會阻止其他類型的初始化,并可能導(dǎo)致死鎖。
您可能想要在方法TcpClient
內(nèi)部Main
構(gòu)造,或者將其構(gòu)造為:
private static readonly TcpClient TcpClient = new TcpClient();
然后主要是:
TcpClient.Connect(...);

TA貢獻(xiàn)1946條經(jīng)驗(yàn) 獲得超3個贊
本例中的靜態(tài)字段初始值設(shè)定項(xiàng)(Program 類)不應(yīng)包含可能拋出或超時的代碼。
問題中突出顯示的代碼是靜態(tài)字段初始值設(shè)定項(xiàng)。這將在第一次訪問類型時運(yùn)行,在任何靜態(tài)方法甚至靜態(tài)構(gòu)造函數(shù)之前運(yùn)行。如果初始值設(shè)定項(xiàng)或靜態(tài)構(gòu)造函數(shù)阻塞或拋出,應(yīng)用程序?qū)⒔K止而不調(diào)用Main
. 這意味著沒有錯誤處理代碼可用于捕獲這些異常。
這種有保證的順序使得在 C# 中實(shí)現(xiàn)簡單的單例變得非常容易。由于執(zhí)行順序得到保證,因此不需要雙重鎖定。查看 Jon Skeet 關(guān)于Singleton implementation的文章:
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton() { }
private Singleton() { }
public static Singleton Instance
{
get
{
return instance;
}
}
}
這足以創(chuàng)建一個線程安全的單例

TA貢獻(xiàn)1818條經(jīng)驗(yàn) 獲得超7個贊
我正在添加一個新的答案,因?yàn)槲以陔[藏類加載和其他初始化異常的更復(fù)雜的托管環(huán)境中遇到了類似的問題。
為了解決這個問題,我這樣做了:
將我的Main方法重命名為Main2,因此它不會與下一個更改沖突。
創(chuàng)建了另一個 Program 類,這次是干凈的,它調(diào)用Main2,如下所示:
class CleanProgram {
static void Main(string[] args) {
try {
Program.Main2(args);
} catch (Exception ex) {
Console.WriteLine("{0}", ex);
}
}
}
上面的更改僅用于診斷目的!找到并解決問題后,可以撤消更改。
- 3 回答
- 0 關(guān)注
- 137 瀏覽
添加回答
舉報(bào)