Exception.Message를 파일에 작성하여 시스템에서 발생하는 모든 예외를 로깅합니다. 그러나 그들은 고객의 문화로 작성되었습니다. 터키의 실수는 나에게 큰 의미가 없습니다.
그렇다면 사용자 문화를 바꾸지 않고 어떻게 오류 메시지를 영어로 기록 할 수 있습니까?
Exception.Message를 파일에 작성하여 시스템에서 발생하는 모든 예외를 로깅합니다. 그러나 그들은 고객의 문화로 작성되었습니다. 터키의 실수는 나에게 큰 의미가 없습니다.
그렇다면 사용자 문화를 바꾸지 않고 어떻게 오류 메시지를 영어로 기록 할 수 있습니까?
답변:
이 문제는 부분적으로 해결 될 수 있습니다. Framework 예외 코드는 현재 스레드 로캘을 기반으로 리소스에서 오류 메시지를로드합니다. 일부 예외의 경우 Message 속성에 액세스 할 때 발생합니다.
이러한 예외가 발생하는 경우 스레드 로캘을 en-US로 간단히 전환하여 로그를 기록하여 메시지의 전체 영어 버전 메시지를 얻을 수 있습니다 (원래의 사용자 로캘을 미리 저장 한 후 바로 복원).
별도의 스레드에서이 작업을 수행하는 것이 더 좋습니다. 이렇게하면 부작용이 발생하지 않습니다. 예를 들면 다음과 같습니다.
try
{
System.IO.StreamReader sr=new System.IO.StreamReader(@"c:\does-not-exist");
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString()); //Will display localized message
ExceptionLogger el = new ExceptionLogger(ex);
System.Threading.Thread t = new System.Threading.Thread(el.DoLog);
t.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
t.Start();
}
ExceptionLogger 클래스는 다음과 같습니다.
class ExceptionLogger
{
Exception _ex;
public ExceptionLogger(Exception ex)
{
_ex = ex;
}
public void DoLog()
{
Console.WriteLine(_ex.ToString()); //Will display en-US message
}
}
그러나 Joe 가이 회신의 이전 개정에 대한 주석에서 올바르게 지적한 것처럼 일부 메시지는 예외가 발생할 때 언어 자원에서 이미 (부분적으로)로드됩니다.
예를 들어 ArgumentNullException ( "foo") 예외가 발생할 때 생성 된 메시지의 '매개 변수가 널일 수 없음'부분에 적용됩니다. 이러한 경우 위의 코드를 사용하더라도 메시지가 여전히 부분적으로 현지화되어 나타납니다.
en-US 로켈이있는 스레드에서 UI가 아닌 모든 코드를 실행하는 등 실용적이 아닌 해킹을 사용하는 것 외에는 할 수있는 일이 많지 않습니다. .NET Framework 예외 코드에는 오류 메시지 로캘을 재정의하는 기능
t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");
하고 t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");
... 결과 예외가 영어이고, 아직
Environment.GetResourceString("...")
솔루션이 더 이상 작동하지 않습니다. 가장 좋은 것은 자신의 (영어) 메시지 텍스트로 사용자 정의 예외를 던지고 InnerException 속성을 사용하여 이전 예외를 유지하는 것입니다.
unlocalize.com 에서 원래 예외 메시지를 검색 할 수 있습니다.
No records found
.
논쟁의 여지가 있지만 문화를로 설정하는 대신로 설정할 en-US
수 있습니다 Invariant
. 에서 Invariant
문화, 오류 메시지가 영어로되어 있습니다.
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
비 미국 영어권 지역에서는 편향적으로 보이지 않는 장점이 있습니다. (일명 동료의 비난을 피함)
catch
.
다음은 코딩이 필요하지 않으며 너무 일찍로드 된 예외 텍스트 (예 : mscorlib의 텍스트)로 변경할 수없는 예외 텍스트에도 작동하는 솔루션입니다.
모든 경우에 항상 적용 가능한 것은 아니지만 (주 .exe 파일과 함께 .config 파일을 만들 수 있어야하기 때문에 설정에 따라 다릅니다) 그러나 그것은 저에게 효과적입니다. 따라서 예를 들어 다음과 같은 줄이 포함 된 app.config
in dev (또는 a [myapp].exe.config
또는 web.config
production)를 만드십시오 .
<configuration>
...
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="mscorlib.resources" publicKeyToken="b77a5c561934e089"
culture="fr" /> <!-- change this to your language -->
<bindingRedirect oldVersion="1.0.0.0-999.0.0.0" newVersion="999.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.resources" publicKeyToken="b77a5c561934e089"
culture="fr" /> <!-- change this to your language -->
<bindingRedirect oldVersion="1.0.0.0-999.0.0.0" newVersion="999.0.0.0"/>
</dependentAssembly>
<!-- add other assemblies and other languages here -->
</assemblyBinding>
</runtime>
...
</configuration>
이 작업은 프레임 워크 에서 프랑스어 (문화는 " " 로 설정 됨)의 프랑스어 (문화는 " " 로 설정 됨 )에서 존재하지 않는 (임의의) 임의의 (임의 mscorlib
의) 리소스 및 리소스에 대한 어셈블리 바인딩을 리디렉션 하도록 지시합니다. 버전 999).System.Xml
fr
따라서 CLR이이 두 어셈블리 (mscorlib 및 System.xml)에 대한 프랑스어 리소스를 찾을 때는 찾지 못하고 정상적으로 영어로 대체됩니다. 상황과 테스트에 따라 이러한 리디렉션 (현지화 된 리소스가 포함 된 어셈블리)에 다른 어셈블리를 추가 할 수 있습니다.
물론 이것이 Microsoft에서 지원한다고 생각하지 않으므로 자신의 책임하에 사용하십시오. 문제를 발견 한 경우이 구성을 제거하고 관련이 없는지 확인할 수 있습니다.
Windows에는 사용하려는 UI 언어가 설치되어 있어야합니다. 번역 된 메시지가 무엇인지 마술처럼 알 수있는 방법은 없습니다.
pt-PT가 설치된 en-US Windows 7 Ultimate에서 다음 코드는 다음과 같습니다.
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("pt-PT");
string msg1 = new DirectoryNotFoundException().Message;
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
string msg2 = new FileNotFoundException().Message;
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
string msg3 = new FileNotFoundException().Message;
pt-PT, en-US 및 en-US로 메시지를 생성합니다. 프랑스어 문화권 파일이 설치되어 있지 않기 때문에 기본적으로 Windows 기본 (설치?) 언어가 사용됩니다.
나는 이것이 오래된 주제라는 것을 알고 있지만 내 솔루션은 웹 검색에서 우연히 발견되는 사람과 관련이 있다고 생각합니다.
예외 로거에서 ex.GetType.ToString을 기록하면 예외 클래스의 이름이 저장됩니다. 클래스의 이름은 언어와 독립적이어야하고 따라서 항상 영어로 표시 될 것으로 기대합니다 (예 : "System.FileNotFoundException"). 현재로서는 외국어 시스템에 액세스 할 수는 없습니다. 생각.
오류 메시지 텍스트를 정말로 원한다면 가능한 모든 예외 클래스 이름과 해당 메시지의 사전을 원하는 언어로 만들 수 있지만 영어의 경우 클래스 이름이 완벽하다고 생각합니다.
InvalidOperationException
의해 던져졌다 System.Xml.XmlWellFormedWriter
. 메시지를 읽지 않고 발생한 특정 오류를 추측하십시오. 천 가지가 될 수 있습니다.
CultureInfo oldCI = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture ("en-US");
Thread.CurrentThread.CurrentUICulture=new CultureInfo("en-US");
try
{
System.IO.StreamReader sr=new System.IO.StreamReader(@"c:\does-not-exist");
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString())
}
Thread.CurrentThread.CurrentCulture = oldCI;
Thread.CurrentThread.CurrentUICulture = oldCI;
해결 방법이 없습니다.
Tks :)
Thread.CurrentThread.CurrentUICulture
예외를 지역화하는 데 설정 이 사용됩니다. 두 종류의 예외가 필요한 경우 (하나는 사용자를 위해, 하나는 사용자를 위해) 다음 함수를 사용하여 예외 메시지를 번역 할 수 있습니다. .NET-Library 리소스에서 리소스 키를 가져온 다음 번역 된 값을 반환하기 위해 원본 텍스트를 검색합니다. 그러나 아직 좋은 해결책을 찾지 못한 한 가지 약점이 있습니다. 리소스에 {0}이 (가) 포함 된 메시지를 찾을 수 없습니다. 누구든지 좋은 해결책이 있다면 감사 할 것입니다.
public static string TranslateExceptionMessage(Exception ex, CultureInfo targetCulture)
{
try
{
Assembly assembly = ex.GetType().Assembly;
ResourceManager resourceManager = new ResourceManager(assembly.GetName().Name, assembly);
ResourceSet originalResources = resourceManager.GetResourceSet(Thread.CurrentThread.CurrentUICulture, createIfNotExists: true, tryParents: true);
ResourceSet targetResources = resourceManager.GetResourceSet(targetCulture, createIfNotExists: true, tryParents: true);
foreach (DictionaryEntry originalResource in originalResources)
if (originalResource.Value.ToString().Equals(ex.Message.ToString(), StringComparison.Ordinal))
return targetResources.GetString(originalResource.Key.ToString(), ignoreCase: false); // success
}
catch { }
return ex.Message; // failed (error or cause it's not smart enough to find texts with '{0}'-patterns)
}
.NET 프레임 워크는 두 부분으로 구성됩니다.
모든 텍스트 (예 : 예외 메시지, MessageBox의 단추 레이블 등)는 .NET 프레임 워크 자체에서 영어로되어 있습니다. 언어 팩에는 현지화 된 텍스트가 있습니다.
정확한 상황에 따라 해결책은 언어 팩을 제거하는 것입니다 (즉, 클라이언트에게 그렇게하도록 지시). 이 경우 예외 텍스트는 영어입니다. 그러나 다른 모든 프레임 워크 제공 텍스트도 영어입니다 (예 : MessageBox의 단추 레이블, ApplicationCommands의 키보드 단축키).
나는 이러한 접근법 중 하나를 상상할 것이다.
예외는 사용자 만 읽을 수 있습니다. 즉, 클라이언트 기능이 아니므로 터키어 모드에서 실행할 때 변경되지 않는 고정 배선 된 현지화되지 않은 문자열을 사용할 수 있습니다.
0x00000001
영어 테이블에서 쉽게 찾을 수 있도록 각 오류에 오류 코드를 포함 하십시오.
Undercover1989 답변을 기반으로하지만 매개 변수 및 메시지가 인수 예외와 같은 여러 리소스 문자열로 구성된시기를 고려합니다.
public static string TranslateExceptionMessage(Exception exception, CultureInfo targetCulture)
{
Assembly a = exception.GetType().Assembly;
ResourceManager rm = new ResourceManager(a.GetName().Name, a);
ResourceSet rsOriginal = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, true, true);
ResourceSet rsTranslated = rm.GetResourceSet(targetCulture, true, true);
var result = exception.Message;
foreach (DictionaryEntry item in rsOriginal)
{
if (!(item.Value is string message))
continue;
string translated = rsTranslated.GetString(item.Key.ToString(), false);
if (!message.Contains("{"))
{
result = result.Replace(message, translated);
}
else
{
var pattern = $"{Regex.Escape(message)}";
pattern = Regex.Replace(pattern, @"\\{([0-9]+)\}", "(?<group$1>.*)");
var regex = new Regex(pattern);
var replacePattern = translated;
replacePattern = Regex.Replace(replacePattern, @"{([0-9]+)}", @"${group$1}");
replacePattern = replacePattern.Replace("\\$", "$");
result = regex.Replace(result, replacePattern);
}
}
return result;
}
나는 같은 상황을 겪었고 여기와 다른 곳에서 찾은 모든 대답은 도움이되지 않거나 만족스럽지 못했습니다.
는 Thread.CurrentUICulture
그물 예외의 언어를 변경하지만,하지의 경우와 Win32Exception
윈도우 UI 자체의 언어로 윈도우 리소스를 사용한다. 따라서 Win32Exception
영어 FormatMessage()
로 Win32Exception을 얻는 방법에 설명 된대로 사용하지 않아도 독일어 대신 영어로 메시지를 인쇄 하지 못했습니다
.
따라서 다른 언어에 대한 대부분의 기존 예외 메시지를 외부 파일에 저장하는 자체 솔루션을 만들었습니다. 원하는 언어로 매우 정확한 메시지를받지는 못하지만 해당 언어로 된 메시지는 현재받는 것보다 훨씬 많습니다 (이해할 수없는 언어로 된 메시지).
이 클래스의 정적 함수는 다른 언어를 사용하는 Windows 설치에서 실행될 수 있습니다
CreateMessages()
. 문화권 별 텍스트를 작성
SaveMessagesToXML()
하면 언어가 작성되거나로드 될 때마다 많은 XML 파일에이를 저장하고
LoadMessagesFromXML()
언어 별 메시지가있는 모든 XML 파일을로드합니다.
다른 언어로 다른 Windows 설치에서 XML 파일을 작성할 때 필요한 모든 언어가 곧 제공 될 것입니다.
여러 MUI 언어 팩이 설치된 경우 1 Windows에서 다른 언어의 텍스트를 만들 수는 있지만 아직 테스트하지는 않았습니다.
VS2008로 테스트되었으며 즉시 사용할 수 있습니다. 의견이나 제안을 환영합니다!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Threading;
using System.Xml;
public struct CException
{
//----------------------------------------------------------------------------
public CException(Exception i_oException)
{
m_oException = i_oException;
m_oCultureInfo = null;
m_sMessage = null;
}
//----------------------------------------------------------------------------
public CException(Exception i_oException, string i_sCulture)
{
m_oException = i_oException;
try
{ m_oCultureInfo = new CultureInfo(i_sCulture); }
catch
{ m_oCultureInfo = CultureInfo.InvariantCulture; }
m_sMessage = null;
}
//----------------------------------------------------------------------------
public CException(Exception i_oException, CultureInfo i_oCultureInfo)
{
m_oException = i_oException;
m_oCultureInfo = i_oCultureInfo == null ? CultureInfo.InvariantCulture : i_oCultureInfo;
m_sMessage = null;
}
//----------------------------------------------------------------------------
// GetMessage
//----------------------------------------------------------------------------
public string GetMessage() { return GetMessage(m_oException, m_oCultureInfo); }
public string GetMessage(String i_sCulture) { return GetMessage(m_oException, i_sCulture); }
public string GetMessage(CultureInfo i_oCultureInfo) { return GetMessage(m_oException, i_oCultureInfo); }
public static string GetMessage(Exception i_oException) { return GetMessage(i_oException, CultureInfo.InvariantCulture); }
public static string GetMessage(Exception i_oException, string i_sCulture)
{
CultureInfo oCultureInfo = null;
try
{ oCultureInfo = new CultureInfo(i_sCulture); }
catch
{ oCultureInfo = CultureInfo.InvariantCulture; }
return GetMessage(i_oException, oCultureInfo);
}
public static string GetMessage(Exception i_oException, CultureInfo i_oCultureInfo)
{
if (i_oException == null) return null;
if (i_oCultureInfo == null) i_oCultureInfo = CultureInfo.InvariantCulture;
if (ms_dictCultureExceptionMessages == null) return null;
if (!ms_dictCultureExceptionMessages.ContainsKey(i_oCultureInfo))
return CreateMessage(i_oException, i_oCultureInfo);
Dictionary<string, string> dictExceptionMessage = ms_dictCultureExceptionMessages[i_oCultureInfo];
string sExceptionName = i_oException.GetType().FullName;
sExceptionName = MakeXMLCompliant(sExceptionName);
Win32Exception oWin32Exception = (Win32Exception)i_oException;
if (oWin32Exception != null)
sExceptionName += "_" + oWin32Exception.NativeErrorCode;
if (dictExceptionMessage.ContainsKey(sExceptionName))
return dictExceptionMessage[sExceptionName];
else
return CreateMessage(i_oException, i_oCultureInfo);
}
//----------------------------------------------------------------------------
// CreateMessages
//----------------------------------------------------------------------------
public static void CreateMessages(CultureInfo i_oCultureInfo)
{
Thread oTH = new Thread(new ThreadStart(CreateMessagesInThread));
if (i_oCultureInfo != null)
{
oTH.CurrentCulture = i_oCultureInfo;
oTH.CurrentUICulture = i_oCultureInfo;
}
oTH.Start();
while (oTH.IsAlive)
{ Thread.Sleep(10); }
}
//----------------------------------------------------------------------------
// LoadMessagesFromXML
//----------------------------------------------------------------------------
public static void LoadMessagesFromXML(string i_sPath, string i_sBaseFilename)
{
if (i_sBaseFilename == null) i_sBaseFilename = msc_sBaseFilename;
string[] asFiles = null;
try
{
asFiles = System.IO.Directory.GetFiles(i_sPath, i_sBaseFilename + "_*.xml");
}
catch { return; }
ms_dictCultureExceptionMessages.Clear();
for (int ixFile = 0; ixFile < asFiles.Length; ixFile++)
{
string sXmlPathFilename = asFiles[ixFile];
XmlDocument xmldoc = new XmlDocument();
try
{
xmldoc.Load(sXmlPathFilename);
XmlNode xmlnodeRoot = xmldoc.SelectSingleNode("/" + msc_sXmlGroup_Root);
string sCulture = xmlnodeRoot.SelectSingleNode(msc_sXmlGroup_Info + "/" + msc_sXmlData_Culture).Value;
CultureInfo oCultureInfo = new CultureInfo(sCulture);
XmlNode xmlnodeMessages = xmlnodeRoot.SelectSingleNode(msc_sXmlGroup_Messages);
XmlNodeList xmlnodelistMessage = xmlnodeMessages.ChildNodes;
Dictionary<string, string> dictExceptionMessage = new Dictionary<string, string>(xmlnodelistMessage.Count + 10);
for (int ixNode = 0; ixNode < xmlnodelistMessage.Count; ixNode++)
dictExceptionMessage.Add(xmlnodelistMessage[ixNode].Name, xmlnodelistMessage[ixNode].InnerText);
ms_dictCultureExceptionMessages.Add(oCultureInfo, dictExceptionMessage);
}
catch
{ return; }
}
}
//----------------------------------------------------------------------------
// SaveMessagesToXML
//----------------------------------------------------------------------------
public static void SaveMessagesToXML(string i_sPath, string i_sBaseFilename)
{
if (i_sBaseFilename == null) i_sBaseFilename = msc_sBaseFilename;
foreach (KeyValuePair<CultureInfo, Dictionary<string, string>> kvpCultureExceptionMessages in ms_dictCultureExceptionMessages)
{
string sXmlPathFilename = i_sPath + i_sBaseFilename + "_" + kvpCultureExceptionMessages.Key.TwoLetterISOLanguageName + ".xml";
Dictionary<string, string> dictExceptionMessage = kvpCultureExceptionMessages.Value;
XmlDocument xmldoc = new XmlDocument();
XmlWriter xmlwriter = null;
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.Indent = true;
try
{
XmlNode xmlnodeRoot = xmldoc.CreateElement(msc_sXmlGroup_Root);
xmldoc.AppendChild(xmlnodeRoot);
XmlNode xmlnodeInfo = xmldoc.CreateElement(msc_sXmlGroup_Info);
XmlNode xmlnodeMessages = xmldoc.CreateElement(msc_sXmlGroup_Messages);
xmlnodeRoot.AppendChild(xmlnodeInfo);
xmlnodeRoot.AppendChild(xmlnodeMessages);
XmlNode xmlnodeCulture = xmldoc.CreateElement(msc_sXmlData_Culture);
xmlnodeCulture.InnerText = kvpCultureExceptionMessages.Key.Name;
xmlnodeInfo.AppendChild(xmlnodeCulture);
foreach (KeyValuePair<string, string> kvpExceptionMessage in dictExceptionMessage)
{
XmlNode xmlnodeMsg = xmldoc.CreateElement(kvpExceptionMessage.Key);
xmlnodeMsg.InnerText = kvpExceptionMessage.Value;
xmlnodeMessages.AppendChild(xmlnodeMsg);
}
xmlwriter = XmlWriter.Create(sXmlPathFilename, writerSettings);
xmldoc.WriteTo(xmlwriter);
}
catch (Exception e)
{ return; }
finally
{ if (xmlwriter != null) xmlwriter.Close(); }
}
}
//----------------------------------------------------------------------------
// CreateMessagesInThread
//----------------------------------------------------------------------------
private static void CreateMessagesInThread()
{
Thread.CurrentThread.Name = "CException.CreateMessagesInThread";
Dictionary<string, string> dictExceptionMessage = new Dictionary<string, string>(0x1000);
GetExceptionMessages(dictExceptionMessage);
GetExceptionMessagesWin32(dictExceptionMessage);
ms_dictCultureExceptionMessages.Add(Thread.CurrentThread.CurrentUICulture, dictExceptionMessage);
}
//----------------------------------------------------------------------------
// GetExceptionTypes
//----------------------------------------------------------------------------
private static List<Type> GetExceptionTypes()
{
Assembly[] aoAssembly = AppDomain.CurrentDomain.GetAssemblies();
List<Type> listoExceptionType = new List<Type>();
Type oExceptionType = typeof(Exception);
for (int ixAssm = 0; ixAssm < aoAssembly.Length; ixAssm++)
{
if (!aoAssembly[ixAssm].GlobalAssemblyCache) continue;
Type[] aoType = aoAssembly[ixAssm].GetTypes();
for (int ixType = 0; ixType < aoType.Length; ixType++)
{
if (aoType[ixType].IsSubclassOf(oExceptionType))
listoExceptionType.Add(aoType[ixType]);
}
}
return listoExceptionType;
}
//----------------------------------------------------------------------------
// GetExceptionMessages
//----------------------------------------------------------------------------
private static void GetExceptionMessages(Dictionary<string, string> i_dictExceptionMessage)
{
List<Type> listoExceptionType = GetExceptionTypes();
for (int ixException = 0; ixException < listoExceptionType.Count; ixException++)
{
Type oExceptionType = listoExceptionType[ixException];
string sExceptionName = MakeXMLCompliant(oExceptionType.FullName);
try
{
if (i_dictExceptionMessage.ContainsKey(sExceptionName))
continue;
Exception e = (Exception)(Activator.CreateInstance(oExceptionType));
i_dictExceptionMessage.Add(sExceptionName, e.Message);
}
catch (Exception)
{ i_dictExceptionMessage.Add(sExceptionName, null); }
}
}
//----------------------------------------------------------------------------
// GetExceptionMessagesWin32
//----------------------------------------------------------------------------
private static void GetExceptionMessagesWin32(Dictionary<string, string> i_dictExceptionMessage)
{
string sTypeName = MakeXMLCompliant(typeof(Win32Exception).FullName) + "_";
for (int iError = 0; iError < 0x4000; iError++) // Win32 errors may range from 0 to 0xFFFF
{
Exception e = new Win32Exception(iError);
if (!e.Message.StartsWith("Unknown error (", StringComparison.OrdinalIgnoreCase))
i_dictExceptionMessage.Add(sTypeName + iError, e.Message);
}
}
//----------------------------------------------------------------------------
// CreateMessage
//----------------------------------------------------------------------------
private static string CreateMessage(Exception i_oException, CultureInfo i_oCultureInfo)
{
CException oEx = new CException(i_oException, i_oCultureInfo);
Thread oTH = new Thread(new ParameterizedThreadStart(CreateMessageInThread));
oTH.Start(oEx);
while (oTH.IsAlive)
{ Thread.Sleep(10); }
return oEx.m_sMessage;
}
//----------------------------------------------------------------------------
// CreateMessageInThread
//----------------------------------------------------------------------------
private static void CreateMessageInThread(Object i_oData)
{
if (i_oData == null) return;
CException oEx = (CException)i_oData;
if (oEx.m_oException == null) return;
Thread.CurrentThread.CurrentUICulture = oEx.m_oCultureInfo == null ? CultureInfo.InvariantCulture : oEx.m_oCultureInfo;
// create new exception in desired culture
Exception e = null;
Win32Exception oWin32Exception = (Win32Exception)(oEx.m_oException);
if (oWin32Exception != null)
e = new Win32Exception(oWin32Exception.NativeErrorCode);
else
{
try
{
e = (Exception)(Activator.CreateInstance(oEx.m_oException.GetType()));
}
catch { }
}
if (e != null)
oEx.m_sMessage = e.Message;
}
//----------------------------------------------------------------------------
// MakeXMLCompliant
// from https://www.w3.org/TR/xml/
//----------------------------------------------------------------------------
private static string MakeXMLCompliant(string i_sName)
{
if (string.IsNullOrEmpty(i_sName))
return "_";
System.Text.StringBuilder oSB = new System.Text.StringBuilder();
for (int ixChar = 0; ixChar < (i_sName == null ? 0 : i_sName.Length); ixChar++)
{
char character = i_sName[ixChar];
if (IsXmlNodeNameCharacterValid(ixChar, character))
oSB.Append(character);
}
if (oSB.Length <= 0)
oSB.Append("_");
return oSB.ToString();
}
//----------------------------------------------------------------------------
private static bool IsXmlNodeNameCharacterValid(int i_ixPos, char i_character)
{
if (i_character == ':') return true;
if (i_character == '_') return true;
if (i_character >= 'A' && i_character <= 'Z') return true;
if (i_character >= 'a' && i_character <= 'z') return true;
if (i_character >= 0x00C0 && i_character <= 0x00D6) return true;
if (i_character >= 0x00D8 && i_character <= 0x00F6) return true;
if (i_character >= 0x00F8 && i_character <= 0x02FF) return true;
if (i_character >= 0x0370 && i_character <= 0x037D) return true;
if (i_character >= 0x037F && i_character <= 0x1FFF) return true;
if (i_character >= 0x200C && i_character <= 0x200D) return true;
if (i_character >= 0x2070 && i_character <= 0x218F) return true;
if (i_character >= 0x2C00 && i_character <= 0x2FEF) return true;
if (i_character >= 0x3001 && i_character <= 0xD7FF) return true;
if (i_character >= 0xF900 && i_character <= 0xFDCF) return true;
if (i_character >= 0xFDF0 && i_character <= 0xFFFD) return true;
// if (i_character >= 0x10000 && i_character <= 0xEFFFF) return true;
if (i_ixPos > 0)
{
if (i_character == '-') return true;
if (i_character == '.') return true;
if (i_character >= '0' && i_character <= '9') return true;
if (i_character == 0xB7) return true;
if (i_character >= 0x0300 && i_character <= 0x036F) return true;
if (i_character >= 0x203F && i_character <= 0x2040) return true;
}
return false;
}
private static string msc_sBaseFilename = "exception_messages";
private static string msc_sXmlGroup_Root = "exception_messages";
private static string msc_sXmlGroup_Info = "info";
private static string msc_sXmlGroup_Messages = "messages";
private static string msc_sXmlData_Culture = "culture";
private Exception m_oException;
private CultureInfo m_oCultureInfo;
private string m_sMessage;
static Dictionary<CultureInfo, Dictionary<string, string>> ms_dictCultureExceptionMessages = new Dictionary<CultureInfo, Dictionary<string, string>>();
}
internal class Program
{
public static void Main()
{
CException.CreateMessages(null);
CException.SaveMessagesToXML(@"d:\temp\", "emsg");
CException.LoadMessagesFromXML(@"d:\temp\", "emsg");
}
}
Thread.CurrentUICulture
또한 그 끔찍한 옵션 만드는 UI의 언어를 변경합니다. 전형적인 예는 메시지 상자의 예 / 아니오 / 확인 / 취소 버튼입니다.
오류 메시지 대신 호출 스택을 기록해야합니다 (IIRC, 간단한 예외. ToString ()이 대신해야합니다). 여기에서 예외가 발생한 위치를 정확하게 판별하고 일반적으로 예외를 추론 할 수 있습니다.
확장 방법을 사용하여 catch 블록에서 예외 메시지를 재정의합니다. Check thrown message는 코드에서 비롯되거나 아래에 언급되지 않은 것입니다.
public static string GetEnglishMessageAndStackTrace(this Exception ex)
{
CultureInfo currentCulture = Thread.CurrentThread.CurrentUICulture;
try
{
dynamic exceptionInstanceLocal = System.Activator.CreateInstance(ex.GetType());
string str;
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
if (ex.Message == exceptionInstanceLocal.Message)
{
dynamic exceptionInstanceENG = System.Activator.CreateInstance(ex.GetType());
str = exceptionInstanceENG.ToString() + ex.StackTrace;
}
else
{
str = ex.ToString();
}
Thread.CurrentThread.CurrentUICulture = currentCulture;
return str;
}
catch (Exception)
{
Thread.CurrentThread.CurrentUICulture = currentCulture;
return ex.ToString();
}
InvalidOperationException
. 메시지 자체없이 그것이 무엇을 의미하는지 알아내는 것이 즐겁습니다. 새로운 인스턴스에는 마법이 없습니다.
로깅을 위해 특정 응용 프로그램은 영어 예외 메시지를 가져와야합니다 (일반 클라이언트의 UICulture에 표시하는 것 외에도).
이를 위해 다음 코드
마지막으로 현재 UICulture를 이전 UICulture로 다시 변경합니다.
try
{
int[] a = { 3, 6 };
Console.WriteLine(a[3]); //Throws index out of bounds exception
System.IO.StreamReader sr = new System.IO.StreamReader(@"c:\does-not-exist"); // throws file not found exception
throw new System.IO.IOException();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Type t = ex.GetType();
CultureInfo CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture;
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
object o = Activator.CreateInstance(t);
System.Threading.Thread.CurrentThread.CurrentUICulture = CurrentUICulture; // Changing the UICulture back to earlier culture
Console.WriteLine(((Exception)o).Message.ToString());
Console.ReadLine();
}