我试着用英语获取所有的Exception消息,不管我的程序在哪种语言上运行。
我从以下文章中获得了几乎所有的英语异常消息:Exception messages in English?和我找到的其他解决方案(比如使用反射更改默认的CultureInfo)。我对SocketException有特殊的问题,不管我在做什么,我都是用默认的机器语言实现的。
我创建了一个测试程序来显示问题:这个测试程序将以默认语言打印异常:
using System;
using System.Text;
using System.Threading;
using System.IO;
using System.Net.Sockets;
using System.Reflection;
using System.Globalization;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
try
{
//I'm not listening on the following port:
TcpClient s = new TcpClient("localhost", 2121);
}
catch (Exception ex)
{
Console.WriteLine("Socket exception: " + ex.Message);
}
try
{
//the following file doesn't exists:
File.ReadAllText("filenotexist.txt");
}
catch (Exception ex)
{
Console.WriteLine("File exception: " + ex.Message);
}
}
}
}这一结果在我的机器上有以下文本:
H:\Shared>Test-def.exe
Socket exception: No connection could be made because the target machine actively refused it 127.0.0.1:2121
File exception: Could not find file 'H:\Shared\filenotexist.txt'.在日本机器上,它用日语写所有的例外(我不明白):
Z:\>Test-def.exe
Socket exception: 対象のコンピューターによって拒否されたため、接続できませんでした。 127.0.0.1:2121
File exception: ファイル 'Z:\filenotexist.txt' が見つかりませんでした。(日语的“\”在日本机器上看起来不一样,但是当复制到我的机器时,它显示为'\')
因此,通过组合我找到的答案,我实现了以下解决方案,现在看起来如下所示:
namespace TestApp
{
class Program
{
//will change CultureInfo to English, this should change all threads CultureInfo to English.
public static void SetEnglishCulture()
{
CultureInfo ci = new CultureInfo("en-US");
//change CultureInfo for current thread:
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture = ci;
//change CultureInfo for new threads:
Type t = typeof(CultureInfo);
try
{
t.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
t.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
}
catch { }
try
{
t.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
t.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
}
catch { }
}
static void Main(string[] args)
{
//first thing: set CultureInfo to English:
SetEnglishCulture();
try
{
//I'm not listening on the following port:
TcpClient s = new TcpClient("localhost", 2121);
}
catch (Exception ex)
{
Console.WriteLine("Socket exception: " + ex.Message);
}
try
{
//the following file doesn't exists:
File.ReadAllText("filenotexist.txt");
}
catch (Exception ex)
{
Console.WriteLine("File exception: " + ex.Message);
}
}
}
}现在,在日本机器上,它用英语编写文件异常,但是Net.socket异常仍然是日语的:
Z:\>Test-en.exe
Socket exception: 対象のコンピューターによって拒否されたため、接続できませんでした。 127.0.0.1:2121
File exception: Could not find file 'Z:\filenotexist.txt'.我还测试了其他一些异常,有些异常现在用英语显示,但不是所有这些异常,套接字异常都是持久的。如您所见,文件异常已经翻译成英文,但套接字异常仍然是日语。
我已经在几乎所有的.NET框架(从2.1到4.5)中测试了它,仍然是相同的。
发布于 2016-01-05 23:12:54
我有一个解决方案,所以我会上传到这里,以防有人需要它。如果有人有更好的解决方案,我会很高兴知道,所以请评论。
在Win32Exception的情况下,我们可以使用FormatMessage并将错误代码翻译成英语和默认语言,并将缺省代码替换为英语。如果我没有替换英语,我就失去了参数。因此,如果替换失败,我将返回异常,并以英语进行补充说明。
以下是我的完整解决方案:
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Globalization;
using System.Reflection;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace TestCulture
{
class Program
{
static void SetEnglishCulture()
{
CultureInfo ci = new CultureInfo("en-US");
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
Type type = typeof(CultureInfo);
try
{
type.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
type.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
} catch { }
try
{
type.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
type.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, ci, new object[] { ci });
} catch { }
}
[DllImport("kernel32.dll")]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, StringBuilder lpBuffer, uint nSize, IntPtr Arguments);
public static string Win32ExceptionInEnglish(Win32Exception ex)
{
const int nCapacity = 820; // max error length
const uint FORMAT_MSG_FROM_SYS = 0x01000;
const uint engLangID = (0x01<<10) | 0x09;
const uint defLangID = 0x0;
StringBuilder engSb = new StringBuilder(nCapacity);
StringBuilder defSb = new StringBuilder(nCapacity);
FormatMessage(FORMAT_MSG_FROM_SYS,IntPtr.Zero, (uint)ex.ErrorCode, defLangID, defSb, nCapacity, IntPtr.Zero);
FormatMessage(FORMAT_MSG_FROM_SYS,IntPtr.Zero, (uint)ex.ErrorCode, engLangID, engSb, nCapacity, IntPtr.Zero);
string sDefMsg = defSb.ToString().TrimEnd(' ','.','\r','\n');
string sEngMsg = engSb.ToString().TrimEnd(' ','.','\r','\n');
if(sDefMsg == sEngMsg) //message already in English (or no english on machine?)
{
//nothing left to do:
return ex.Message;
}
else
{
string msg = ex.Message.Replace(sDefMsg,sEngMsg);
if (msg == ex.Message)
{
//replace didn't worked, can be message with arguments in the middle.
//I such as case print both: original and translated. to not lose the arguments.
return ex.Message + " (In English: " + sEngMsg + ")";
}
else
{
//successfuly replaced!
return msg;
}
}
}
public static void Main(string[] args)
{
SetEnglishCulture();
try {
// generate any exception ...
const int notListenningPort = 2121;
new TcpClient("localhost", notListenningPort);
}
catch(Win32Exception ex)//first try to cach win32 Exceptions
{
Console.WriteLine("W32 Exception: " + Win32ExceptionInEnglish(ex));
}
catch(Exception ex)//this fit to the rest .NET exceptions which affected by CultureInfo
{
Console.WriteLine("Exception: " +ex.Message);
}
}
}
}发布于 2015-12-22 23:59:43
SocketException是Win32Exception。与从Win32Exception派生的所有其他类一样,它使用Win32Exception.GetErrorMessage(int error)从Windows获取消息,后者在Kernel32.DLL中使用FormatMessage。
这样做,消息实际上来自Windows,而不是来自.NET。Windows将以Windows语言返回一条消息,而AFAIK,您在.NET程序中对此无能为力。
发布于 2015-12-23 00:18:27
您可能必须将打印错误的行包装到另一个线程中,该线程的区域设置为英语,因为Framework异常代码将根据当前线程区域设置从其资源中加载错误消息。下面是我在一些代码中所讲的内容:
static void Main(string[] args) {
try {
TcpClient c = new TcpClient("localhost", 1234);
}
catch (Exception ex) {
// thread that logs exception message to console
Thread logger = new Thread(new ParameterizedThreadStart(PrintException));
logger.CurrentCulture = new System.Globalization.CultureInfo("en-US");
logger.Start(ex);
}
}
private static void PrintException(object ex) {
Console.WriteLine("Error: " + ((Exception)ex).Message);
}https://stackoverflow.com/questions/34423129
复制相似问题