英文异常消息?


298

我们通过将Exception.Message写入文件来记录系统中发生的所有异常。但是,它们是按照客户的文化来编写的。土耳其语的错误对我来说意义不大。

那么,如何在不改变用户文化的情况下用英语记录错误消息呢?


8
您为什么不能这样:CultureInfo oldCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(“ en”); //在这里抛出新的异常=>文化用英语Thread.CurrentThread.CurrentCulture = oldCulture;
CheGueVerra

93
我不知道开发者,这是幸福的非英语类异常报文:S ..
Zéiksz

3
@Zéiksz超越英语国家,您会发现很多:D。问题不是非英语文本,问题是您无法理解的语言。以您的母语(假定正确翻译)发送的消息非常好。
亚历杭德罗

31
@Alejandro不得不将异常消息从一种母语翻译成英语才能用谷歌搜索,这是一个更大的麻烦。恕我直言。
Antoine Meltzheim '17

18
Microsoft的哪个白痴曾想过只翻译适用于开发人员的错误消息。甚至翻译了编程语言中使用的术语(例如字典中的键)。(未在词典中找到关键字,在荷兰语的de bibliotheek中的niet gevonden中成为Sleutel)。我不想为此更改操作系统语言...
Roel

Answers:


66

此问题可以部分解决。框架异常代码根据当前线程语言环境从其资源加载错误消息。在某些情况下,这是在访问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”)异常时生成的消息的“参数不能为null”部分。在这些情况下,即使使用上面的代码,消息仍将(部分)本地化。

除了通过使用不切实际的技巧(例如,在以en-US语言环境开始的线程上运行所有非UI代码)之外,您似乎无能为力:.NET Framework异常代码没有覆盖错误消息语言环境的工具。


10
您的示例适用于FileNotFoundException,因为在访问Message属性时而不是在引发异常时检索消息资源。但这并非适用于所有异常(例如,尝试抛出新的ArgumentNullException(“ paramName”))

3
我很困惑。我已尝试按照您的回答进行测试,并测试它是否希望以法语显示我的例外情况,所以我做到了t.CurrentUICulture = new System.Globalization.CultureInfo("fr-FR");t.CurrentCulture = new System.Globalization.CultureInfo("fr-FR");但是,最终的例外情况是英语...
VitalyB 2011年

7
@VitalyB本地化的异常文本是.NET Framework语言包的一部分。因此,如果您没有安装法语包,则不会获得翻译后的文本。
Daniel Rose

7
至少使用.NET 4.5实例化所有异常,Environment.GetResourceString("...")因此您的解决方案不再起作用。最好的办法是使用您自己的(英语)消息文本引发自定义异常,并使用InnerException属性保留旧的异常。
webber2k6

1
获得异常类型名称的反思可能会变得很方便。
吉列尔莫·普兰迪

67

您可以在unlocalize.com上搜索原始异常消息。


5
试图搜索一些中文异常消息,总是告诉我No records found
泰勒·隆

1
不好的选择。当我将例外发送到Google Analytics(分析)(或其他云服务)时,对于相同的例外,但是语言不同,我将拥有不同的例外组。而且我将无法按每个异常的计数进行排序,因为它不能反映实际计数(英语为100,汉语为77,朝鲜语为80 ...等等)
Artemious

我记得当我只是将本地化的异常消息转储到Google时,曾经多次找到这个漂亮的网站,但现在不再可用。
Martin Braun

40

也许这是一个有争议的观点,但是en-US您可以将其设置为,而不是将文化设置为Invariant。在Invariant文化中,错误消息是英文的。

Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;

它具有不显得偏见的优点,尤其是对于非美国英语地区。(也避免了同事的sn亵言论)


1
我们应该在ASP.NET项目中的哪几行写这些行?谢谢。
杰森

2
我将建议在顶部的Application_Start中。这将使整个项目以英语运行。如果仅是您想要的错误消息,则可以创建Cover函数并在每个函数中调用它catch
MPelletier '16

5
但是,这是否也会使标准的消息框按钮变为英语?这可能不是我们期望的行为。
Nyerguds

12

这是一种不需要任何编码的解决方案,甚至可以处理异常文本,因为这些文本加载得太早,以至于我们无法通过代码进行更改(例如,mscorlib中的异常)。

它可能并不总是适用于每种情况(它取决于您的设置,因为您需要能够在主.exe文件旁边创建一个.config文件),但它对我有用。因此,只需创建一个包含以下几行的app.configin dev(或a [myapp].exe.configweb.config生产中):

<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>

这是告诉框架将法语资源(介于1和999之间的版本)的mscorlib's资源和System.Xml's资源的程序集绑定重定向fr到...不存在的程序集(任意999版)。

因此,当CLR为这两个程序集(mscorlib和System.xml)寻找法语资源时,它将找不到它们并优雅地回退为英语。根据您的上下文和测试,您可能想要向这些重定向添加其他程序集(包含本地化资源的程序集)。

当然,我认为这不受Microsoft支持,因此使用时后果自负。好吧,如果您发现问题,则可以删除此配置并检查它是否无关。


1
需要测试运行程序工具的英语输出时有效。
smg

试过这个,但是对我没用。.net中还有其他资源文件吗?在哪里可以找到它们?
BluE

1
在c:\ Windows \ Microsoft.NET \ Framework \ v4.0.30319中查找。每种语言都有2个字母的文件夹。请记住,将上面答案中的“ fr”替换为实际使用的语言。“ no”代表挪威语,“ da”代表丹麦语,“ s​​v”代表瑞典语等
。– Wolf5

要创建完整列表,请查看该文件夹。它大约有120个资源文件。将它们每个都添加到配置中。这似乎是目前Windows 10及更高版本的唯一解决方案,因为不再有方法可以在较新的Windows(操作系统的一部分)中卸载.Net语言包。现在甚至将其放置在GAC中,因此删除这些语言文件夹似乎不起作用。
Wolf5

10

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默认(已安装?)语言。


这样就解决了问题。在我的情况下,波兰语用户界面使用Vistalizator程序安装了MUI语言包〜260MB。
Krzysztof Szynter 2011年

5

我知道这是一个老话题,但是我认为我的解决方案可能与在网络搜索中偶然发现它的任何人有关:

在异常记录器中,您可以记录ex.GetType.ToString,这将保存异常类的名称。我希望类的名称应独立于语言,因此始终以英语表示(例如“ System.FileNotFoundException”),尽管目前我无法访问外语系统来测试理念。

如果您也确实想要错误消息文本,则可以使用您喜欢的任何一种语言创建一个词典,其中包含所有可能的异常类名称及其等效消息,但是对于英语,我认为该类名称已足够。


5
不起作用 我被InvalidOperationException扔了System.Xml.XmlWellFormedWriter。您尝试猜测发生了什么特定错误,而不阅读消息。可能是一千种不同的东西。
Nyerguds

4
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 :)


你忘记了;
KansaiRobot

4

设置Thread.CurrentThread.CurrentUICulture将用于本地化异常。如果您需要两种异常(一种针对用户,一种针对您),则可以使用以下函数来转换异常消息。它在.NET-Libraries资源中搜索原始文本,以获取资源密钥,然后返回转换后的值。但是有一个缺点,我还没有找到一个好的解决方案:找不到资源中包含{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)
}

如果异常包含格式化的参数,那将行不通。
Nick Berardi 2015年

是的,就像我说的:“但是有一个缺点,我还没有找到一个好的解决方案:找不到包含资源{0}的消息。如果有人有一个好的解决方案,我将不胜感激。”
Vortex852456 2015年

3

.NET框架分为两个部分:

  1. .NET框架本身
  2. .NET框架语言包

.NET框架本身中的所有文本(例如,异常消息,MessageBox上的按钮标签等)都是英语。语言包具有本地化的文本。

根据您的实际情况,一种解决方案是卸载语言包(即告诉客户端这样做)。在这种情况下,例外文本将为英文。但是请注意,所有其他框架提供的文本也将是英语(例如,MessageBox上的按钮标签,ApplicationCommands的键盘快捷键)。


谢谢!!具有讽刺意味的是,卸载对话框使用的是卸载包的语言,而不是本地语言。旁注:语言包似乎每几个月返回一次。我还没有弄清楚为什么,但是我正在猜测更新/升级
Choco Smith

@ChocoSmith通过Windows Update对.NET Framework进行每次更新时,都会再次安装语言包。
丹尼尔·罗斯

5
要求客户卸载自己语言的语言包不是一个可行的解决方案。
Nyerguds

2

我可以想象其中一种方法:

  1. 异常仅由您读取,即它们不是客户端功能,因此您可以使用在土耳其语模式下运行时不会更改的硬连线非本地化字符串。

  2. 包括一个错误代码,例如0x00000001每个错误,以便您可以轻松地在英语表中查找它。


9
当.net框架的内部组件抛出异常时,这并没有多大帮助。整个问题不适用于您抛出的异常;显然程序员选什么样的信息,包括与那些
Nyerguds

1

基于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;
}

1

我遇到过同样的情况,在这里和其他地方找到的所有答案都没有帮助或不满意:

Thread.CurrentUICulture改变了.NET异常的语言,但它并不适用于Win32Exception,它使用Windows资源在Windows UI本身的语言。因此,我从未设法Win32Exception用英语而不是德语来打印消息,甚至没有FormatMessage()按照如何获取英语中的Win32Exception中所述使用消息进行打印

因此,我创建了自己的解决方案,该解决方案将大多数不同语言的现有异常消息存储在外部文件中。您不会以所需的语言得到非常准确的消息,但是会以该语言得到一条消息,该消息比您当前所获得的消息要多得多(这是您可能不理解的语言的消息)。

此类的静态功能可以在Windows安装中使用不同的语言来执行: CreateMessages()创建特定于文化的文本,
SaveMessagesToXML()将其保存到创建语言或加载
LoadMessagesFromXML()时所保存的XML文件中,并加载所有具有特定于语言的消息的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");
  }
}

1
Thread.CurrentUICulture 改变了用户界面的语言,使其成为一个可怕的选择。一个经典的例子是消息框中的是/否/确定/取消按钮。
Nyerguds

0

英文异常消息

try
{
    ......
}
catch (Exception ex)
{
      throw new UserFriendlyException(L("ExceptionmessagesinEnglish"));
}

然后转到本地化文件夹并将其放置在projectName.xml中并添加

<text name="ExceptionmessagesinEnglish">Exception Message in English</text>

-1

您应该记录调用堆栈,而不仅仅是错误消息(IIRC,简单的exception.ToString()应该为您完成此操作)。从那里,您可以准确确定异常的来源,通常可以推断出异常是什么。


3
我们正在记录消息和堆栈跟踪。但是,如果消息很清楚,则容易得多。
卡拉

-1

使用扩展方法覆盖catch块中的异常消息,如下所述,检查抛出的消息是否来自代码。

    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();
        }

1
就像我之前说的那样InvalidOperationException。弄清楚没有消息本身的含义,这很有趣。一个新实例不会神奇地拥有它。
Nyerguds

-1

为了进行日志记录,某些应用程序可能需要获取英语异常消息(除了在常规客户端的UICulture中显示之外)。

为此,下面的代码

  1. 更改当前的UICulture
  2. 使用“ GetType()”和“ Activator.CreateInstance(t)”重新创建抛出的Exception对象
  3. 在新的UICuture中显示新的Exception对象的Message
  4. 然后最后将当前的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();
    
         }

1
这不能保证新对象的异常消息与引发的异常相同。它可能完全不同,通常也完全不同。这就是为什么我们需要异常消息。
Artemious
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.