如何使用Roslyn成功编译带标记/标记的类

时间:2019-03-28 10:40:50

标签: c# attributes roslyn

我正在为一个想要将给定对象序列化/反序列化为XML的客户工作,反之亦然。他不会用属性([XmlElement],[XmlArray]等)标记所有类,这在我看来是最好的解决方案,因此他想使用给定的对象生成一个动态类,这意味着编写具有相同声明属性的新类,并添加属性以进行序列化。新类使用StringBuilder编写,之后必须进行编译并获取新实例。问题在于,如果我编写用于序列化的属性,则不会编译该新类,但是如果删除属性,则该类将成功编译,并且可以获得实例。

此处是代码

dynamicClassCode = @"
using System.Xml.Serialization;

namespace Pat.Infrastructure.Communication.Model
{
   public class RequestMessage_Serializable
   {
      [XmlElement]
      public System.DateTime RequestDateTime { get; set; }

      [XmlElement]  
      public System.String RequestUniqueMessageId { get; set; }

      [XmlElement]  
      public System.Version Version { get; set; }

      [XmlElement]  
      public System.String User { get; set; }

      [XmlElement]  
      public System.String Password { get; set; }

      [XmlElement]
      public System.String Terminal { get; set; }

      [XmlElement]
      public System.String Method { get; set; }

      [XmlElement]
      public System.Object Request { get; set; }

      [XmlElement]
      public System.String RequestType { get; set; }

      [XmlElement]
      public System.String EndPointSource { get; set; }

      [XmlElement]
      public System.String ResponseFormatExpected { get; set; }

      [XmlElement]
      public System.Object Configuration { get; set; }

      [XmlElement]
      public System.Boolean OneWay { get; set; }
   }
}"

string runtimePath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\{0}.dll";
var syntaxTree = CSharpSyntaxTree.ParseText(dynamicClassCode);

IEnumerable<MetadataReference> DefaultReferences = new[] {MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Xml")),
                        MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Xml.Serialization")),
                        MetadataReference.CreateFromFile(typeof(object).Assembly.Location)
                        };

CSharpCompilation compilation = CSharpCompilation.Create("DynamicCodeManager",
                new[] { syntaxTree },
                DefaultReferences,
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

using (var dllStream = new MemoryStream())
using (var pdbStream = new MemoryStream())
{
  var emitResult = compilation.Emit(dllStream, pdbStream);
  if (!emitResult.Success)
  {
    var diag = emitResult.Diagnostics;
  }
  else
  {
    dllStream.Seek(0, SeekOrigin.Begin);
    Assembly assembly = Assembly.Load(dllStream.ToArray());
   List<System.Reflection.TypeInfo> typesDeclared = new List<System.Reflection.TypeInfo>(assembly.DefinedTypes);
                    Type type = assembly.GetType(typesDeclared[0].ToString());
                    dynamicObj = Activator.CreateInstance(type);
  }
}

我收到的消息如下:[0](7,8):错误CS0246:否否否否XmlElementAttributeAttribute属性不正确(使用正确的引用或引用? )Microsoft.CodeAnalysis.Diagnostic {Microsoft.CodeAnalysis.CSharp.CSDiagnostic}

有什么主意吗? 预先感谢。

2 个答案:

答案 0 :(得分:0)

关于这个具体问题:

您需要确保包括所有必需的引用,并且所有引用都来自同一运行时(目录)。

这对我有用:

IEnumerable<MetadataReference> DefaultReferences = new[] {
            MetadataReference.CreateFromFile(string.Format(runtimePath, "mscorlib")),
            MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Runtime")),
            MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Xml")),
            MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Xml.Serialization")),
            MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Xml.XmlSerializer"))
            };

请注意,您拥有的以下代码很可能会从“ runtimePath”以外的其他目录中加载mscorlib程序集,从而加载不兼容的程序集。

MetadataReference.CreateFromFile(typeof(object).Assembly.Location)

答案 1 :(得分:0)

关于您的原始问题:

首先,您不需要将类序列化为XML的属性。默认情况下,序列化程序将自动序列化所有公共属性和字段。仅当您想要偏离默认行为时,才需要使用属性来控制序列化。

但是,然后,您不需要在运行时创建动态类型来控制XML序列化。您可以使用XmlAttributeOverrides类来模拟具有xml序列化控件属性的特定类型,如文档中所述:

XmlAttributeOverrides Class