繁体   English   中英

为什么连接调试器时,即时编译的C#代码不起作用?

[英]Why does C# code compiled on the fly not work when a debugger is attached?

我有以下C#项目,目标是.NET 4.0,它接受源代码文件,动态地将其编译成一个程序集,然后执行该程序集中包含的类型的静态方法。

这可以按预期工作,只要我没有附加调试器启动程序。 在这种情况下,我在调用xmlSerializer.Serialize(sw, family);遇到异常xmlSerializer.Serialize(sw, family); 更确切地说, System.InvalidOperationException内的System.TypeInitializationException内的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并查看是否有任何程序集无法在那里解析。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM