我有以下C#项目定位.NET 4.0,它接受一个源代码文件,即时将其编译成程序集,然后执行该程序集中包含的类型的静态方法.
这是按预期工作的,只要我没有启动与调试器连接的程序.在这种情况下,我会在System.InvalidOperationException中的System.TypeInitializationException内调用xmlSerializer.Serialize(sw,family);更准确地说是System.NullReferenceException异常.
如果我使用相同的程序,将源代码文件包含在项目中并将其直接编译到主程序集合中,不管是否附加了调试器,我将不会收到异常.
请注意,我的项目引用了与在编译时列出的完全相同的程序集.
为什么编写的代码对于编译是否重要,无论调试器是否附加?我失踪了什么
主文件Program.cs:
using System; using System.CodeDom.Compiler; using System.IO; using System.Reflection; using System.Linq; namespace DebugSerializeCompiler { class Program { static void Main() { if (!Environment.GetCommandLineArgs().Contains("Compile")) { DebugSerializeCompiler.SerializerTest.Run(); } else { Assembly assembly; if (TryCompile("..\\..\\SerializerTest.cs",new[]{ "Microsoft.CSharp.dll","System.dll","System.Core.dll","System.Data.dll","System.Xml.dll" },out assembly)) { Type type = assembly.GetType("DebugSerializeCompiler.SerializerTest"); MethodInfo methodInfo = type.GetMethod("Run"); methodInfo.Invoke(null,null); } } Console.ReadKey(); } static bool TryCompile(string fileName,string[] referencedAssemblies,out Assembly assembly) { bool result; CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp"); var compilerparams = new CompilerParameters { GenerateExecutable = false,GenerateInMemory = true }; foreach (var referencedAssembly in referencedAssemblies) { compilerparams.ReferencedAssemblies.Add(referencedAssembly); } using (var reader = new StreamReader(fileName)) { CompilerResults compilerResults = compiler.CompileAssemblyFromSource(compilerparams,reader.ReadToEnd()); assembly = compilerResults.CompiledAssembly; result = !compilerResults.Errors.HasErrors; if (!result) { Console.Out.WriteLine("Compiler Errors:"); foreach (CompilerError error in compilerResults.Errors) { Console.Out.WriteLine("Position {0}.{1}: {2}",error.Line,error.Column,error.ErrorText); } } } return result; } } }
文件编译成单独的程序集SerializerTest.cs:
using System; using System.Collections.Generic; using System.IO; using System.Xml.Serialization; namespace DebugSerializeCompiler { public class SerializerTest { public static void Run() { Console.WriteLine("Executing Run()"); var family = new Family(); var xmlSerializer = new XmlSerializer(typeof(Family)); TextWriter sw = new StringWriter(); try { if (sw == null) Console.WriteLine("sw == null"); if (family == null) Console.WriteLine("family == null"); if (xmlSerializer == null) Console.WriteLine("xmlSerializer == null"); xmlSerializer.Serialize(sw,family); } catch (Exception e) { Console.WriteLine("Exception caught:"); Console.WriteLine(e); } Console.WriteLine(sw); } } [Serializable] public class Family { public string LastName { get; set; } public List<FamilyMember> FamilyMembers { get; set; } } [Serializable] public class FamilyMember { public string FirstName { get; set; } } }
这是用于在Windows 7上使用Visual C#2010 Express编译项目的csproj文件:
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">x86</Platform> <ProductVersion>8.0.30703</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{7B8D2187-4C58-4310-AC69-9F87107C25AA}</ProjectGuid> <OutputType>Exe</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>DebugSerializeCompiler</RootNamespace> <AssemblyName>DebugSerializeCompiler</AssemblyName> <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> <TargetFrameworkProfile>Client</TargetFrameworkProfile> <FileAlignment>512</FileAlignment> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PlatformTarget>x86</PlatformTarget> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> <PlatformTarget>x86</PlatformTarget> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Data" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Compile Include="Program.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="SerializerTest.cs"> <SubType>Code</SubType> </Compile> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process,add your task inside one of the targets below and uncomment it. Other similar extension points exist,see Microsoft.Common.targets. <Target Name="BeforeBuild"> </Target> <Target Name="AfterBuild"> </Target> --> </Project>
解决方法
对我来说很好.
但是,如果我不得不猜测你正在发生什么,那就是因为你正在使用你的主项目来编译这个类,并动态地编译它,所以序列化程序对于使用哪个程序集是失败的.您可以尝试将事件附加到AppDomain.CurrentDomain.AssemblyResolve,并查看是否有任何程序集无法解析.