如何解决如何使用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://xgenplus.codeplex.com/)的东西来生成通常在运行时执行的代码。然后,将其添加到解决方案中,并将其作为解决方案的一部分进行编译。那时,对象是否在内部都没有关系-您可以在同一名称空间中添加预生成的代码。由于其全部预先生成,因此其性能飞速发展。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。