我有以下针对.NET 4.0的C#项目,它接受源代码文件,动态地将其编译成一个程序集,然后执行该程序集中包含的类型的静态方法。
只要我没有附加调试器启动程序,这就可以正常工作了。在这种情况下,我在调用xmlSerializer.Serialize(sw, family);
时会遇到异常,更确切地说是System.NullReferenceException
内System.TypeInitializationException
内的System.InvalidOperationException
。
如果我采用相同的程序,在项目中包含源代码文件并将其直接编译到主程序集中,无论是否附加调试器,我都不会得到异常。
请注意,我的项目引用了与动态编译时列出的完全相同的程序集。
为什么动态编译的代码是否附加了调试器?我错过了什么?
主档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>
答案 0 :(得分:2)
它对我来说很好。
但是,如果我不得不猜测你发生了什么,那就是因为你正在用你的主项目编译类并动态编译它,序列化器对于使用哪个程序集并且失败感到困惑。您可以尝试将事件附加到AppDomain.CurrentDomain.AssemblyResolve
,并查看是否有任何程序集无法解决。