微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用XmlSerializer序列化内部类?

如何解决如何使用XmlSerializer序列化内部类?

| 我正在建立一个与第三方接口的库。通过XML和HTTP帖子进行通信。那行得通。 但是,无论使用库的任何代码,都无需了解内部类。我的内部对象使用以下方法序列化为XML:
internal static string SerializeXML(Object obj)
{
    XmlSerializer serializer = new XmlSerializer(obj.GetType(),\"some.domain\");

    //settings
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.OmitXmlDeclaration = true;

    using (StringWriter stream = new StringWriter())
    {
        using (XmlWriter writer = XmlWriter.Create(stream,settings))
        {
            serializer.Serialize(writer,obj);
        }
        return stream.ToString();
    }
}
但是,当我将类的访问修饰符更改为
internal
时,在运行时会出现异常:   [system.invalidOperationException] = {\“ MyNamespace.MyClass由于其保护级别而无法访问。只能处理公共类型。”“ 该异常发生在上面代码的第一行。 我希望我的图书馆的课程不要公开,因为我不想公开它们。我可以那样做吗?如何使用通用序列化程序使内部类型可序列化?我究竟做错了什么?     

解决方法

        来自Sowmy Srinivasan的博客-使用XmlSerializer序列化内部类型:   能够序列化内部类型是常见的要求之一   由XmlSerializer团队看到。这是人们的合理要求   运输库。他们不想使XmlSerializer类型   只是为了序列化程序而公开。我最近从   将XmlSerializer编写给消耗   XmlSerializer。当我遇到类似的要求时,我说:“没办法。   使用DataContractSerializer \“。      原因很简单。 XmlSerializer通过生成代码来工作。的   生成的代码位于动态生成的程序集中,并且需要   访问要序列化的类型。自从XmlSerializer开发以来   在轻量级代码生成问世之前,   生成的代码无法访问除公共类型中的任何内容   另一个程序集。因此,要序列化的类型必须是公共的。      我听见精明的读者耳语:“如果   \'InternalsVisibleTo \'属性已使用\“。      我说:“对,但是生成的程序集的名称未知   前期。您要使哪个内部零件可见?\“      敏锐的读者:\“如果使用\'sgen.exe \',则程序集名称是已知的”      我:\“为了使sgen能够为您的类型生成序列化程序,它们必须是   上市\”      敏锐的读者:\“我们可以进行两遍编译。   类型为public的sgen和类型为as的另一张运送证   内部。”      他们可能是对的!如果我请精明的读者给我写一个样本   他们可能会写这样的东西。 (免责声明:这是   不是官方的解决方案。 YMMV)
using System;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.CompilerServices;
using System.Reflection;

[assembly: InternalsVisibleTo(\"Program.XmlSerializers\")]

namespace InternalTypesInXmlSerializer
{
    class Program
    {
        static void Main(string[] args)
        {
            Address address = new Address();
            address.Street = \"One Microsoft Way\";
            address.City = \"Redmond\";
            address.Zip = 98053;
            Order order = new Order();
            order.BillTo = address;
            order.ShipTo = address;

            XmlSerializer xmlSerializer = GetSerializer(typeof(Order));
            xmlSerializer.Serialize(Console.Out,order);
        }

        static XmlSerializer GetSerializer(Type type)
        {
#if Pass1
            return new XmlSerializer(type);
#else
            Assembly serializersDll = Assembly.Load(\"Program.XmlSerializers\");
            Type xmlSerializerFactoryType = serializersDll.GetType(\"Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract\");

            MethodInfo getSerializerMethod = xmlSerializerFactoryType.GetMethod(\"GetSerializer\",BindingFlags.Public | BindingFlags.Instance);

            return (XmlSerializer)getSerializerMethod.Invoke(Activator.CreateInstance(xmlSerializerFactoryType),new object[] { type });

#endif
        }
    }

#if Pass1
    public class Address
#else
    internal class Address
#endif
    {
        public string Street;
        public string City;
        public int Zip;
    }

#if Pass1
    public class Order
#else
    internal class Order
#endif
    {
        public Address ShipTo;
        public Address BillTo;
    }
} 
  一些精明的“黑客”读者可能会把我的build.cmd交给我   进行编译。
csc /d:Pass1 program.cs

sgen program.exe

csc program.cs
    ,        作为替代方案,您可以使用动态创建的公共类(不会向第三者公开):
static void Main()
{
    var emailType = CreateEmailType();

    dynamic email = Activator.CreateInstance(emailType);

    email.From = \"x@xpto.com\";
    email.To = \"y@acme.com\";
    email.Subject = \"Dynamic Type\";
    email.Boby = \"XmlSerializer can use this!\";
}

static Type CreateEmailType()
{
    var assemblyName = new AssemblyName(\"DynamicAssembly\");

    var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.Run);

    var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);

    var typeBuilder = moduleBuilder.DefineType(
        \"Email\",(
            TypeAttributes.Public |
            TypeAttributes.Sealed |
            TypeAttributes.SequentialLayout |
            TypeAttributes.Serializable
        ),typeof(ValueType)
    );

    typeBuilder.DefineField(\"From\",typeof(string),FieldAttributes.Public);
    typeBuilder.DefineField(\"To\",FieldAttributes.Public);
    typeBuilder.DefineField(\"Subject\",FieldAttributes.Public);
    typeBuilder.DefineField(\"Body\",FieldAttributes.Public);

    return typeBuilder.CreateType();
}
    ,        这可能会帮助您:MRB_ObjectSaver 该项目可帮助您将c#中的任何对象保存/加载/克隆到文件/字符串中/从文件/字符串中复制。与“ c#序列化”相比,此方法保留对对象的引用,并且对象之间的链接不会中断。 (有关示例,请参见:SerializeObjectTest.cs)此外,该类型尚未标记为[Serializable]     ,        您还可以使用称为xgenplus(http://xge​​nplus.codeplex.com/)的东西来生成通常在运行时执行的代码。然后,将其添加到解决方案中,并将其作为解决方案的一部分进行编译。那时,对象是否在内部都没有关系-您可以在同一名称空间中添加预生成的代码。由于其全部预先生成,因此其性能飞速发展。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。