什么是System.TypeInitializationException错误,如何修复?

47
private static void Main(string[] args)
{
    string str = null;
    Logger.InitUserLogWithRotation();            // <--- error occur
    ...
}

我编译项目时没有错误,但在执行时却总是崩溃。

我尝试通过调试项目,但在第一行就出现了 System.TypeInitializationException 错误。

我已经尝试搜索过谷歌,但没有找到解决方案。

看起来像是某个变量初始化的代码有问题,但找不到具体原因。

请帮帮我,我是C#新手。

谢谢。

※ 这里是Logger类的代码:

public class Logger
{
    private static int HDLOG_PRIORITY_DEBUG = 4;
    private static int HDLOG_PRIORITY_ERROR = 1;
    private static int HDLOG_PRIORITY_FATAL = 0;
    private static int HDLOG_PRIORITY_INFO = 3;
    private static int HDLOG_PRIORITY_WARNING = 2;
    public static int LOG_LEVEL_DEBUG = 4;
    public static int LOG_LEVEL_ERROR = 2;
    public static int LOG_LEVEL_FATAL = 1;
    public static int LOG_LEVEL_INFO = 5;
    public static int LOG_LEVEL_WARNING = 3;
    private static string s_bstCommonAppData = Path.Combine(s_commonAppData, "XXXX");
    private static string s_bstUserDataDir = Path.Combine(s_bstCommonAppData, "UserData");
    private static string s_commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
    private static bool s_consoleLogging = false;
    private static FileStream s_fileStream;
    public static HdLoggerCallback s_HdLoggerCallback;
    private static string s_logDir = null;
    private static string s_logFileName = "XXXX";
    private static string s_logFilePath = null;
    public static int s_logFileSize = 0xa00000;
    private static bool s_loggerInited = false;
    private static string s_logLevels = null;
    private static int s_logRotationTime = 0x7530;
    private static string s_logStringDebug = "DEBUG";
    private static string s_logStringError = "ERROR";
    private static string s_logStringFatal = "FATAL";
    private static string s_logStringInfo = "INFO";
    private static string s_logStringWarning = "WARNING";
    private static int s_processId = -1;
    private static string s_processName = "Unknown";
    private static object s_sync = new object();
    public static int s_totalLogFileNum = 5;
    private static TextWriter writer = Console.Error;

    private static void Close()
    {
        if (!s_consoleLogging)
        {
            writer.Close();
            s_fileStream.Dispose();
            writer.Dispose();
        }
    }

    public static void Debug(string msg)
    {
        Debug("{0}", new object[] { msg });
    }

    public static void Debug(string fmt, params object[] args)
    {
        Print(LOG_LEVEL_DEBUG, s_processName, fmt, args);
    }

    private static void DoLogRotation()
    {
    Label_0000:
        Thread.Sleep(s_logRotationTime);
        try
        {
            lock (s_sync)
            {
                FileInfo info = new FileInfo(s_logFilePath);
                if (info.Length >= s_logFileSize)
                {
                    string destFileName = s_logFilePath + ".1";
                    string path = s_logFilePath + "." + s_totalLogFileNum;
                    if (File.Exists(path))
                    {
                        File.Delete(path);
                    }
                    for (int i = s_totalLogFileNum - 1; i >= 1; i--)
                    {
                        string str3 = s_logFilePath + "." + i;
                        string str4 = s_logFilePath + "." + (i + 1);
                        if (File.Exists(str3))
                        {
                            File.Move(str3, str4);
                        }
                    }
                    File.Move(s_logFilePath, destFileName);
                }
            }
            goto Label_0000;
        }
        catch (Exception)
        {
            goto Label_0000;
        }
    }

    public static void Error(string msg)
    {
        Error("{0}", new object[] { msg });
    }

    public static void Error(string fmt, params object[] args)
    {
        Print(LOG_LEVEL_ERROR, s_processName, fmt, args);
    }

    public static void Fatal(string msg)
    {
        Fatal("{0}", new object[] { msg });
    }

    public static void Fatal(string fmt, params object[] args)
    {
        Print(LOG_LEVEL_FATAL, s_processName, fmt, args);
    }

    private static string GetLogDir(bool userSpecificLog)
    {
        string str;
        if (s_logDir != null)
        {
            return s_logDir;
        }
        try
        {
            if (userSpecificLog)
            {
                str = Path.Combine(s_bstUserDataDir, "Logs");
            }
            else
            {
                str = (string) Registry.LocalMachine.OpenSubKey(@"Software\XXXX").GetValue("LogDir");
            }
        }
        catch (Exception)
        {
            str = Path.Combine(s_bstUserDataDir, "Logs");
        }
        s_logDir = str;
        return str;
    }

    private static string GetPrefix(string tag, string logLevel)
    {
        int managedThreadId = Thread.CurrentThread.ManagedThreadId;
        DateTime now = DateTime.Now;
        return string.Format("{0:D4}-{1:D2}-{2:D2} {3:D2}:{4:D2}:{5:D2}.{6:D3} {7}:{8:X8} ({9}). {10}: ", new object[] { now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond, s_processId, managedThreadId, tag, logLevel });
    }

    public static TextWriter GetWriter()
    {
        return new Writer(delegate (string msg) {
            Print(msg);
        });
    }

    private static void HdLogger(int prio, uint tid, string tag, string msg)
    {
        int level = 0;
        if (prio == HDLOG_PRIORITY_FATAL)
        {
            level = LOG_LEVEL_FATAL;
        }
        else if (prio == HDLOG_PRIORITY_ERROR)
        {
            level = LOG_LEVEL_ERROR;
        }
        else if (prio == HDLOG_PRIORITY_WARNING)
        {
            level = LOG_LEVEL_WARNING;
        }
        else if (prio == HDLOG_PRIORITY_INFO)
        {
            level = LOG_LEVEL_INFO;
        }
        else if (prio == HDLOG_PRIORITY_DEBUG)
        {
            level = LOG_LEVEL_DEBUG;
        }
        Print(level, tag, "{0:X8}: {1}", new object[] { tid, msg });
    }

    public static void Info(string msg)
    {
        Info("{0}", new object[] { msg });
    }

    public static void Info(string fmt, params object[] args)
    {
        Print(LOG_LEVEL_INFO, s_processName, fmt, args);
    }

    public static void InitConsoleLog()
    {
        InitLog("-", true, false);
    }

    public static void InitLog(string logFileName, bool userSpecificLog, bool doLogRotation)
    {
        s_loggerInited = true;
        s_HdLoggerCallback = new HdLoggerCallback(Logger.HdLogger);
        s_processId = Process.GetCurrentProcess().Id;
        s_processName = Process.GetCurrentProcess().ProcessName;
        if (logFileName == "-")
        {
            writer = Console.Error;
            s_consoleLogging = true;
        }
        else
        {
            if (logFileName == null)
            {
                logFileName = s_logFileName;
            }
            if (userSpecificLog)
            {
                logFileName = logFileName + "Users";
            }
            string logDir = GetLogDir(userSpecificLog);
            string str2 = string.Format(@"{0}\{1}.log", logDir, logFileName);
            if (!Directory.Exists(logDir))
            {
                Directory.CreateDirectory(logDir);
            }
            s_logFilePath = str2;
            LogLevelsInit();
            lock (s_sync)
            {
                Open();
            }
            if (doLogRotation)
            {
                new Thread(() => DoLogRotation()) { IsBackground = true }.Start();
            }
        }
    }

    public static void InitSystemLog()
    {
        InitLog(null, false, false);
    }

    public static void InitSystemLogWithRotation()
    {
        InitLog(null, false, true);
    }

    public static void InitUserLog()
    {
        InitLog(null, true, false);
    }

    public static void InitUserLogWithRotation()
    {
        InitLog(null, true, true);
    }

    private static bool IsLogLevelEnabled(string tag, string level)
    {
        if (s_logLevels == null)
        {
            return false;
        }
        return (s_logLevels.StartsWith("ALL") || s_logLevels.Contains((tag + ":" + level).ToUpper()));
    }

    private static void LogLevelsInit()
    {
        string name = @"Software\XXXX\Config";
        try
        {
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(name))
            {
                s_logLevels = (string) key.GetValue("DebugLogs");
            }
        }
        catch (Exception)
        {
            return;
        }
        if (s_logLevels != null)
        {
            s_logLevels = s_logLevels.ToUpper();
        }
    }

    private static void Open()
    {
        if (!s_consoleLogging)
        {
            if (!s_loggerInited)
            {
                InitLog("-", false, false);
                s_loggerInited = true;
            }
            else
            {
                s_fileStream = new FileStream(s_logFilePath, FileMode.Append, FileAccess.Write, FileShare.Delete | FileShare.ReadWrite);
                writer = new StreamWriter(s_fileStream, Encoding.UTF8);
            }
        }
    }

    public static void Print(string msg)
    {
        Print("{0}", new object[] { msg });
    }

    public static void Print(string fmt, params object[] args)
    {
        Print(LOG_LEVEL_INFO, s_processName, fmt, args);
    }

    public static void Print(int level, string tag, string fmt, params object[] args)
    {
        string str = "UNKNOWN";
        if (level == LOG_LEVEL_FATAL)
        {
            str = s_logStringFatal;
        }
        else if (level == LOG_LEVEL_ERROR)
        {
            str = s_logStringError;
        }
        else if (level == LOG_LEVEL_WARNING)
        {
            str = s_logStringWarning;
        }
        else if (level == LOG_LEVEL_INFO)
        {
            str = s_logStringInfo;
        }
        else if (level == LOG_LEVEL_DEBUG)
        {
            str = s_logStringDebug;
        }
        if ((level != LOG_LEVEL_DEBUG) || IsLogLevelEnabled(tag, str))
        {
            lock (s_sync)
            {
                Open();
                writer.WriteLine(GetPrefix(tag, str) + fmt, args);
                writer.Flush();
                Close();
            }
        }
    }

    public static void SetLogDir(string logDir)
    {
        s_logDir = logDir;
    }

    public static void Warning(string msg)
    {
        Warning("{0}", new object[] { msg });
    }

    public static void Warning(string fmt, params object[] args)
    {
        Print(LOG_LEVEL_WARNING, s_processName, fmt, args);
    }

    public delegate void HdLoggerCallback(int prio, uint tid, string tag, string msg);

    public class Writer : TextWriter
    {
        private WriteFunc writeFunc;

        public Writer(WriteFunc writeFunc)
        {
            this.writeFunc = writeFunc;
        }

        public override void WriteLine(string msg)
        {
            this.writeFunc(msg);
        }

        public override void WriteLine(string fmt, object obj)
        {
            this.writeFunc(string.Format(fmt, obj));
        }

        public override void WriteLine(string fmt, object[] objs)
        {
            this.writeFunc(string.Format(fmt, objs));
        }

        public override System.Text.Encoding Encoding
        {
            get
            {
                return System.Text.Encoding.UTF8;
            }
        }

        public delegate void WriteFunc(string msg);
    }
}

6
查看“InnerException”以获得准确的异常信息。 - Rohit Vats
3
点击“调试(Debug)”菜单,选择“异常(Exceptions)”,并勾选所有的“抛出(Thrown)”复选框。这样可以帮助您确定问题所在。 - Bala Kumar
12个回答

39

每当抛出 TypeInitializationException 异常时,请在抛出异常的语句中首次引用该类型时检查该类型的所有初始化逻辑 - 在您的情况下为:Logger

初始化逻辑包括:类型的静态构造函数(如果我没有遗漏的话,你对于 Logger 并没有这个函数)和字段初始化。

Logger 中字段初始化基本上都是“非关键”的,除了以下几行代码:

private static string s_bstCommonAppData = Path.Combine(s_commonAppData, "XXXX");
private static string s_bstUserDataDir = Path.Combine(s_bstCommonAppData, "UserData");
private static string s_commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

s_commonAppData 在调用 Path.Combine(s_commonAppData, "XXXX"); 的时候是 null。据我所知,这些初始化按照您编写它们的 确切 顺序发生 - 所以请将 s_commonAppData 上移至少两行 ;)


20

System.TypeInitializationException发生在加载类型的过程中执行代码时抛出异常。

当.NET加载类型时,必须在您使用该类型的第一次之前准备所有静态字段。有时,初始化需要运行代码。当该代码失败时,就会出现System.TypeInitializationException

在您特定的情况下,以下三个静态字段运行了一些代码:

private static string s_bstCommonAppData = Path.Combine(s_commonAppData, "XXXX");
private static string s_bstUserDataDir = Path.Combine(s_bstCommonAppData, "UserData");
private static string s_commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

请注意,s_bstCommonAppData 依赖于 s_commonAppData,但它先于其依赖项声明。因此,在调用 Path.Combine 时,s_commonAppData 的值为 null,从而导致 ArgumentNullException。对于 s_bstUserDataDirs_bstCommonAppData 也是如此:它们的声明顺序与初始化所需的顺序相反。

重新排列这些行以解决问题:

private static string s_commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
private static string s_bstCommonAppData = Path.Combine(s_commonAppData, "XXXX");
private static string s_bstUserDataDir = Path.Combine(s_bstCommonAppData, "UserData");

6

这些行是你的问题(或者至少是你的一个问题,如果有更多问题的话):

private static string s_bstCommonAppData = Path.Combine(s_commonAppData, "XXXX");
private static string s_bstUserDataDir = Path.Combine(s_bstCommonAppData, "UserData");
private static string s_commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

您在其他静态成员的初始化器中引用了一些静态成员。这是一个不好的做法,因为编译器不知道它们的初始化顺序。结果是,在初始化s_bstCommonAppData期间,依赖的字段s_commonAppData尚未被初始化,因此您正在调用Path.Combine(null, "XXXX"),而这个方法不接受空参数。
您可以通过确保在其他字段的初始化中使用的字段首先声明来解决这个问题:
private static string s_commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
private static string s_bstCommonAppData = Path.Combine(s_commonAppData, "XXXX");
private static string s_bstUserDataDir = Path.Combine(s_bstCommonAppData, "UserData");

或者使用静态构造函数来显式地排序这些赋值语句:
private static string s_bstCommonAppData;
private static string s_bstUserDataDir;
private static string s_commonAppData;

static Logger()
{
    s_commonAppData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
    s_bstCommonAppData = Path.Combine(s_commonAppData, "XXXX");
    s_bstUserDataDir = Path.Combine(s_bstCommonAppData, "UserData");
}

“在其他静态成员的初始化器中引用了一些静态成员”对我来说是关键解决方案。那正是我所做的。这个错误非常罕见和零散,可能是由于静态类初始化的随机顺序造成的。谢谢! - Eric Sassaman

4

i. 请查看 TypeInitializationExceptionInnerException 属性。

ii. 此问题也可能是由于程序集的运行时版本不匹配引起的。请验证主程序集(调用应用程序)与所引用的程序集的运行时版本是否一致。


2
我知道这是一个有点老的问题,但最近我遇到了这个错误,所以我想分享我的解决方案。
我的错误似乎源于旧的App.Config文件和从.Net 4.0升级到.Net 4.5.1的“就地”升级。
当我在升级到Framework 4.5.1后启动旧项目时,我立即遇到了TypeInitializationException,甚至无法运行一行代码。
在创建了一个全新的wpf项目进行测试之后,我发现新的App.Config文件需要以下内容。
  <configSections>
    <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="YourAppName.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
    </sectionGroup>
  </configSections>  

一旦我添加了这个,我就可以开始工作了。

请注意您的需求可能会略有不同。我会创建一个虚拟项目,检查生成的App.Config文件,看看是否还有其他缺失的内容。

希望这对某些人有所帮助。快乐编码!


2
如果您在appsetting中有自定义属性,请将其移动
     <configSections> 
     </configSections>

标签添加到<configuration>的第一个子元素中。


2
我在我的.NET框架4项目的app.config中遇到了System.TypeInitializationException,因为存在一个错误。感谢pStan让我检查app.config。我的configSections已经被正确定义。但是,在其中一个section中未定义的元素导致了异常的抛出。
问题就在于app.config中的问题可能会生成这个非常误导性的TypeInitializationException。
通过等待进入方法而不是代码的类级别来访问配置值,可以通过相同的app.config错误生成更有意义的ConfigurationErrorsException。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Collections.Specialized;

namespace ConfigTest
{
    class Program
    {
        public static string machinename;
        public static string hostname;
        public static NameValueCollection _AppSettings;

        static void Main(string[] args)
        {
            machinename = System.Net.Dns.GetHostName().ToLower();
            hostname = "abc.com";// System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).HostName.ToLower().Replace(machinename + ".", "");
            _AppSettings = ConfigurationManager.GetSection("domain/" + hostname) as System.Collections.Specialized.NameValueCollection;
        }
    }
}

1
对我来说,像 Dal.isPhoneNumberInUse("some string number") 这样的简单函数抛出了这个异常。这让我感到很奇怪,因为在几行之前,Dal 已经被使用了多次。 最后我意识到问题出在传递给该函数的参数上,它是 dynamic 类型的,而我应该将其解析为字符串。

:

Dal.isPhoneNumberInUse(data.phoneNumber) //not good
Dal.isPhoneNumberInUse((string)data.phoneNumber);//good

当然,您需要验证data.phoneNumber是字符串/对象类型而不是结构体。


0

我遇到了system.typeintialzationException错误,这是因为我尝试移动文件时出现了问题:

 File.Move(DestinationFilePath, SourceFilePath)

那个错误是因为我实际上交换了路径,正确的路径是:

 File.Move(SourceFilePath, DestinationFilePath)

0
我曾经遇到过这个问题。正如所述,这可能是一个静态声明问题。在我的情况下,是因为我在 DEBUG 子句中使用了静态变量。也就是说(在 C# 中):
#if DEBUG
    public static bool DOTHISISINDEBUGONLY = false;
#endif

一切都很正常,直到我编译了代码的发布版本,之后我遇到了这个错误 - 即使是旧的发布版本也是如此。一旦我将变量从DEBUG子句中移除,一切恢复正常。


1
你在谈论编译错误,但是 OP 在运行时遇到了问题,所以你的情况在这里不适用。 - Gian Paolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接