当前位置: 首页 > 编程语言 > C#

未知类的序列化与还原分享

时间:2023-04-10 15:39:54 C#

未知类的序列化与还原基础工程包含抽象基类Foo。在一个单独的客户端项目中,有一些类实现了这个基类。我想通过在基类上调用一些方法来序列化和恢复具体类的实例://在基础项目中:publicabstractclassFoo{abstractvoidSave(stringpath);抽象FooLoad(字符串路径);}假设在反序列化时,所有需要的类都存在。如果可能,应以XML格式进行序列化。可以使基类实现IXmlSerializable。我有点被困在这里。如果我理解正确的话,这只能通过将[XmlInclude(typeof(UnknownClass))]添加到每个实现类的基类来实现——但是实现类是未知的!有没有办法做到这一点?我没有反思的经验,但我也欢迎使用它来回答。编辑:问题是反序列化。只是序列化会很容易。?您还可以通过在构造函数中提供额外的详细信息来创建XmlSerializer。请注意,它不会重用此类模型,因此您需要配置XmlSerializer一次(在应用程序启动时,从配置中),并重复使用它...请注意,XmlAttributeOverrides重载可能允许更多自定义...使用usingSystem.集合.通用;使用System.IO;使用System.Xml.Serialization;静态类程序{staticreadonlyXmlSerializerser;staticProgram(){列表extraTypes=newList();//TODO:读取配置,或使用反射//查看所有程序集extraTypes.Add(typeof(Bar));ser=newXmlSerializer(typeof(Foo),extraTypes.ToArray());}staticvoidMain(){Foofoo=newBar();MemoryStreamms=newMemoryStream();ser.Serialize(ms,foo);ms.Position=0;Fooclone=(Foo)ser.Deserialize(ms);Console.WriteLine(clone.GetType());}publicabstractclassFoo{}publicclassBar:Foo{}除了将序列化函数放入任何基类之外,您还可以将其添加到Utility类中。例如(代码仅供参考,rootName可选)publicstaticclassUtility{publicstaticvoidToXml(Tsrc,stringrootName,stringfileName)whereT:class,new(){XmlSerializerserializer=newXmlSerializer(typeof(T),新的XmlRootAttribute(rootName));XmlTextWriterwriter=newXmlTextWriter(fileName,Encoding.UTF8);serializer.Serialize(writer,src);writer.Flush();writer.Close();Utility.ToXml(fooObj,"Foo",@"c:foo.xml");不仅Foo家族类型可以使用它,所有其他可序列化对象也可以使用它。编辑OK全服务...(rootName是可选的)publicstaticTFromXml(Tsrc,stringrootName,stringfileName)whereT:class,new(){XmlSerializerserializer=newXmlSerializer(typeof(T),newXmlRootAttribute(rootName));TextReaderreader=newStreamReader(文件名);返回serializer.Deserialize(reader)作为T;}序列化应该不是问题,XmlSerializer构造函数采用Type参数,甚至通过抽象基上的方法在派生类的实例上调用GetType将返回派生类型的实际类型。所以基本上,只要在反序列化时知道正确的类型,那么序列化正确的类型就很简单了。因此,您可以在顶部实现一个名为serialize的方法,或者将此方法传递给XmlSerializer的构造函数。或者只是传递当前引用并让序列化方法处理它,你应该没问题。编辑:更新OP的编辑。如果您不知道要反序列化的类型,那么您实际上只有一个字符串或字节数组,没有某种标识符,那么您就在某处小溪上。您可以尝试反序列化xx基类的每个已知派生类型,我不推荐这样做。您的另一个选择是手动遍历XML并通过将类型作为属性或您有什么来重构对象,也许这就是您在帖子中最初的意思,但现在我认为内置序列化没有办法在不指定案件类型的情况下执行此操作会为您处理。在XML命名空间的深处有一个很棒的类,称为XmlReflectionImporter。如果您需要在运行时创建模式,这可能会对您有所帮助。您还可以通过在构造函数中创建所有可能类型的XmlSerializerpassign来完成此操作。注意,当你使用这个构造函数时,每次都会编译xmlSerializer,如果你一直重新创建它会导致泄漏。您将需要创建一个序列化程序并在您的应用程序中重用它。然后您可以引导序列化程序并使用反射来查找foo的任何后代。这些链接可能对您有所帮助:我有一个复杂的远程处理项目并且希望对序列化的XML有非常严格的控制。服务器可以接收它不知道如何反序列化的对象,反之亦然,因此我需要一种快速识别它们的方法。我尝试过的所有.NET解决方案都缺乏我的项目所需的灵活性。我在基本xml中存储了一个int属性来标识对象的类型。如果我需要从xml创建一个新对象,我创建一个检查类型属性的工厂类,然后创建相应的派生类并将其提供给xml。我做了这样的事情(拉内存,所以语法可能有点偏离):(1)创建一个接口interfaceISerialize{stringToXml();voidFromXml(字符串xml);};(2)基类publicclassBase:ISerialize{publicenumType{Base,Derived};公共类型m_type;publicBase(){m_type=Type.Base;}publicvirtualstringToXml(){stringxml;//将类Base序列化为XML返回字符串;}publicvirtualvoidFromXml(stringxml){//从xml更新对象Base}};(3)派生类publicclassDerived:Base,ISerialize{publicDerived(){m_type=Type.Derived;}publicoverridevirtualstringToXml(){stringxml;//将类Base序列化为XMLxml=base.ToXml();//现在将Derived序列化为XML返回字符串;}publicoverridevirtualvoidFromXml(stringxml){//从xml更新对象Base.FromXml(xml);//更新派生自xml}};(4)对象工厂publicObjectFactory{publicstaticBaseCreate(stringxml){Baseo=null;基础.类型t;//从xml中提取Base.Typeswitch(t){caseBase.Type.Derived:o=newDerived();o.FromXml(xml);休息;}返回o;}};此方法读取XML根元素并检查当前执行的程序集是否包含具有此类名称的类型,如果是,则反序列化XML文档。如果不是,则会抛出错误。publicstaticTFromXml(stringxmlString){类型sourceType;使用(varstringReader=newStringReader(xmlString)){varrootNodeName=XElement.Load(stringReader).Name.LocalName;sourceType=Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t=>t.IsSubclassOf(typeof(T))&&t.Name==rootNodeName)??Assembly.GetAssembly(typeof(T)).GetTypes().FirstOrDefault(t=>t.IsSubclassOf(typeof(T))&&t.Name==rootNodeName);if(sourceType==null){thrownewException();}}使用(varstringReader=newStringReader(xmlString)){if(sourceType.IsSubclassOf(typeof(T))||sourceType==typeof(T)){varser=newXmlSerializer(sourceType);使用(varxmlReader=newXmlTextReader(stringReader)){Tobj;obj=(T)ser.Deserialize(xmlReader);xmlReader.Close();返回对象;}}else{thrownewInvalidCastException(sourceType.FullName+"cannotbecastto"+typeof(T).FullName);}}}将类标记为Serializable并使用SoapBinaryFormatter而不是XmlS序列化器在序列化时会自动为你提供这个函数,将序列化实例的类型信息写入XML,SoapBinaryFormatter在反序列化时可以实例化子类。我使用未知(但预期)类的XmlType属性来确定反序列化类型。在AbstractXmlSerializer类的实例化期间加载预期类型并将其放入字典中。在反序列化期间,根元素被读取并用于从字典中检索类型。之后,它反序列化很好。XmlMessage.class:publicabstractclassXmlMessage{}IdleMessage.class:[XmlType("idle")]publicclassIdleMessage:XmlMessage{[XmlElement(ElementName="id",IsNullable=true)]publicstringMessageId{get;放;}}AbstractXmlSerializer.class:publicclassAbstractXmlSerializerwhereAbstractType:class{privateDictionarytypeMap;publicAbstractXmlSerializer(列表类型){typeMap=newDictionary();foreach(Typetypeintypes){if(type.IsSubclassOf(typeof(AbstractType))){object[]attributes=type.GetCustomAttributes(typeof(XmlTypeAttribute),false);if(attributes!=null&&attributes.Count()>0){XmlTypeAttributeattribute=attributes[0]asXmlTypeAttribute;typeMap[属性.TypeName]=类型;}}}}publicAbstractTypeDeserialize(StringxmlData){if(string.IsNullOrEmpty(xmlData)){thrownewArgumentException("xmlData参数必须包含xml");}//读取数据,反序列化基于(现在知道n)具体类型。使用(StringReaderstringReader=newStringReader(xmlData)){使用(XmlReaderxmlReader=XmlReader.Create(stringReader)){StringtargetType=GetRootElementName(xmlReader);if(targetType==null){thrownewInvalidOperationException("未找到XML根元素");}AbstractType结果=(AbstractType)newXmlSerializer(typeMap[targetType]).Deserialize(xmlReader);返回结果;}}}privatestaticstringGetRootElementName(XmlReaderxmlReader){if(xmlReader.IsStartElement()){returnxmlReader.Name;}返回空值;}}单元测试:以上就是C#学习教程:未知类的序列化与回收的全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注——[TestMethod]publicvoidTestMethod1(){ListextraTypes=newList();extraTypes.Add(typeof(IdleMessage));AbstractXmlSerializerser=newAbstractXmlSerializer(extraTypes);字符串xmlMsg="";MutcMessage结果=ser.反序列化(xmlMsg);断言。IsTrue(结果为IdleMessage);}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如有转载请注明出处: