gpt4 book ai didi

.net - 抽象类的序列化

转载 作者:行者123 更新时间:2023-12-03 22:51:08 25 4
gpt4 key购买 nike

我正在尝试序列化,但我正面临 abstact 类的问题。

我用谷歌搜索答案,我找到了 this blogitem .
我试过那个和那个工作。

好的,很不错。但请查看对该项目的评论:

This methodology seems to be hiding the true problem and that is an inaccurate implementation of OO design patterns, namely the factory pattern.

Having to change the base class to reference any new factory class is self-defeating.

With a little after-thought, the code can be changed to where any derived type can be associated with the abstract class (through the miracle of interfaces) and no XmlInclude would be required.

I suggest further research into factory patterns which seems to be what you are trying to implement here.



评论者在说什么?他有点含糊。有人可以更详细地解释一下吗(举个例子)?还是他只是在胡说八道?

更新(阅读第一个答案后)

为什么评论者会谈论

factory pattern





the code can be changed to where any derived type can be associated with the abstract class (through the miracle of interfaces)



?

他要不要做一个这样的界面?
public interface IWorkaround
{
void Method();
}

public class SomeBase : IWorkaround
{
public void Method()
{
// some logic here
}
}

public class SomeConcrete : SomeBase, IWorkaround
{
public new void Method()
{
base.Method();
}
}

最佳答案

他既对又错。

诸如 BinaryFormatter 之类的东西,这不是问题;序列化流包含完整的类型元数据,因此如果您有:

[Serializable] abstract class SomeBase {}
[Serializable] class SomeConcrete : SomeBase {}
...
SomeBase obj = new SomeConcrete();

并序列化 obj ,然后在流中包含“我是 SomeConcrete”。这使生活变得简单,但很冗长,尤其是在重复时。它也很脆弱,因为它在反序列化时需要相同的实现;对不同的客户端/服务器实现或长期存储都不利。

XmlSerializer (我猜博客正在谈论),没有元数据 - 但元素名称(或 xsi:type 属性)用于帮助识别使用的是哪个。为此,序列化程序 需要提前知道哪些名称映射到哪些类型。

最简单的方法是用我们知道的子类装饰基类。然后,序列化程序可以检查这些(以及任何其他特定于 xml 的属性)中的每一个,以确定何时看到 <someConcreteType>元素,映射到 SomeConcrete实例(请注意,名称不需要匹配,因此不能仅按名称查找)。
[XmlInclude(typeof(SomeConcrete))]
public abstract class SomeBase {}
public class SomeConcrete : SomeBase {}
...
SomeBase obj = new SomeConcrete();
XmlSerializer ser = new XmlSerializer(typeof(SomeBase));
ser.Serialize(Console.Out, obj);

然而,如果他是一个纯粹主义者(或者数据不可用),那么还有另一种选择;您可以通过重载的构造函数将所有这些数据分别指定为 XmlSerializer .例如,您可以从配置(或者可能是 IoC 容器)中查找一组已知子类型,并手动设置构造函数。这不是很棘手,但它足够棘手以至于不值得,除非您 真的需要它 .
public abstract class SomeBase { } // no [XmlInclude]
public class SomeConcrete : SomeBase { }
...
SomeBase obj = new SomeConcrete();
Type[] extras = {typeof(SomeConcrete)}; // from config
XmlSerializer ser = new XmlSerializer(typeof(SomeBase), extras);
ser.Serialize(Console.Out, obj);

此外,还有 XmlSerializer如果您使用自定义 ctor 路由,重要的是缓存和重用 XmlSerializer实例;否则每次使用都会加载一个新的动态程序集 - 非常昂贵(它们无法卸载)。如果您使用简单的构造函数,它会缓存并重用模型,因此只使用单个模型。

YAGNI 规定我们应该选择最简单的选项;使用 [XmlInclude]不需要复杂的构造函数,也不需要担心缓存序列化程序。不过,另一个选项是存在的并且完全受支持。

回复您的后续问题:

通过“工厂模式”,他说的是你的代码 的情况。不知道 SomeConcrete ,也许是由于 IoC/DI 或类似的框架;所以你可能有:
SomeBase obj = MyFactory.Create(typeof(SomeBase), someArgsMaybe);

哪个算出合适的 SomeBase具体实现,实例化它并将其交还。显然,如果我们的代码不知 Prop 体类型(因为它们只在配置文件中指定),那么我们就不能使用 XmlInclude ;但是我们可以解析配置数据并使用 ctor 方法(如上所述)。实际上,大多数时候 XmlSerializer与 POCO/DTO 实体一起使用,因此这是一个人为的关注点。

并重新接口(interface);同样的事情,但更灵活(接口(interface)不需要类型层次结构)。但是 XmlSerializer不支持这种模式。坦率地说,强硬;那不是它的工作。它的工作是允许您存储和传输数据。不是执行。任何 xml-schema 生成的实体都不会 方法。数据是具体的,而不是抽象的。只要你认为“DTO”,接口(interface)争论就不是问题。因无法在其边界上使用接口(interface)而烦恼的人还没有接受关注点分离,即他们正试图这样做:
Client runtime entities <---transport---> Server runtime entities

而不是限制较少
Client runtime entities <---> Client DTO <--- transport--->
Server DTO <---> Server runtime entities

现在,在许多(大多数?)情况下,DTO 和实体 可以 是相同的;但是如果你想做一些运输不喜欢的事情,引入一个 DTO;不要与序列化程序作斗争。当人们努力编写他们的对象时,同样的逻辑适用:
class Person {
public string AddressLine1 {get;set;}
public string AddressLine2 {get;set;}
}

作为表单的xml:
<person>
<address line1="..." line2="..."/>
</person>

如果你想要这个,引入一个对应于传输的 DTO,并在你的实体和 DTO 之间进行映射:
// (in a different namespace for the DTO stuff)
[XmlType("person"), XmlRoot("person")]
public class Person {
[XmlElement("address")]
public Address Address {get;set;}
}
public class Address {
[XmlAttribute("line1")] public string Line1 {get;set;}
[XmlAttribute("line2")] public string Line2 {get;set;}
}

这也适用于所有其他琐事,例如:
  • 为什么我需要一个无参数的构造函数?
  • 为什么我的集合属性需要一个 setter?
  • 为什么我不能使用不可变类型?
  • 为什么我的类型必须是公开的?
  • 我如何处理复杂的版本控制?
  • 如何处理具有不同数据布局的不同客户端?
  • 为什么我不能使用接口(interface)?
  • 等等

  • 你并不总是有这些问题;但是如果你这样做 - 引入一个(或几个)DTO,你的问题就会消失。回到关于接口(interface)的问题; DTO 类型可能不是基于接口(interface)的,但您的运行时/业务类型可以。

    关于.net - 抽象类的序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1327064/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com