2

我正在尝试编写一个文件头,它是一个表示某些对象层次结构的 XML 字符串。

此层次结构在某些点包含子类型,例如,类Plant包含类型的属性Stem,但在序列化时,Root值可以是任何子类的实例Stem,例如LongStemDryStemRottenStem。此外,还有一个属性Collection<LeafBase> Leaves,其项目可以是 的任何子类型LeafBase,例如GreenLeaf,SweetLeaf等。

如果我只使用默认代码,DataContractSerializer 将给出一个运行时错误,抱怨“意外类型”,因为它需要一个类型的对象Stem并接收一个类型DryStem,例如。

因此,一些研究很快将我引向了 Known Types 解决方案,它要求我在目标类型的每个子类中包含一个数组(天知道还有多少层)。

嗯,这在我看来是对 DRY 和 SRP 原则的严重违反,因为如果每次我添加一个子类,我都必须在我的源代码中查找要更新的已知类型列表(这是 Shotgun Surgery 反模式,并且是该系统先前版本的最差特征之一)。

我已经看到了一种使用反射并获得已知类型列表的方法,但我猜这有点骇人听闻(我不在乎),所以我的问题是:

关于 DRY 和已知类型列表问题,对于对象树包含大量继承的类,处理 DataContractSerialization 的好方法是什么?

或者,如果有另一种类型安全的方法可以将对象序列化和反序列化为 XML 字符串,并且不受此问题的影响,那么这可能是一种选择。

4

1 回答 1

2

如果我正确理解您的意思,您可以通过在运行时发现派生基类的所有类型来避免每次创建新子类型时重复声明子类型。

类似于以下内容:

[KnownType("GetKnownTypes")]
public abstract class Foo
{
    public static Type[] GetKnownTypes()
    {
        Type currentType = MethodBase.GetCurrentMethod().DeclaringType;
        return currentType.Assembly.GetTypes()
                                   .Where(t => t.IsSubclassOf(currentType))
                                   .ToArray();
    }
}

这将允许您在运行时设置所有已知类型,而无需KnownTypes在每个派生类型上复制您的属性。

编辑:

您能否建议一种从解决方案中的每个程序集中获取类型的方法,而不仅仅是声明基类的类型?

假设您有一个单独AppDomain的程序集,您可以 search AppDomain.CurrentDomain.GetAssemblies(),它将迭代当前 AppDomain 中所有已加载程序集的所有类型:

public static Type[] GetKnownTypes()
{
    Type currentType = MethodBase.GetCurrentMethod().DeclaringType;
    return AppDomain.CurrentDomain.GetAssemblies()
                                  .SelectMany(x => x.DefinedTypes)
                                  .Where(x => x.IsSubclassOf(currentType))
                                  .ToArray();
}
于 2015-05-18T13:46:40.647 回答