我正在尝试编写一个文件头,它是一个表示某个对象层次结构的XML字符串。
某些点的此层次结构包含子类型,例如,类Plant
包含类型Stem
的属性,但在序列化时,Root
值可以是任何子类的实例Stem
,LongStem
,DryStem
或RottenStem
。此外,还有一个属性Collection<LeafBase> Leaves
,其项目可以是LeafBase
的任何子类型,例如GreenLeaf
,SweetLeaf
等。
如果我只使用默认代码,DataContractSerializer会给出一个抱怨&#34;意外类型&#34;的运行时错误,因为它需要类型为Stem
的对象并收到类型DryStem
相反,例如。
因此,一些研究很快引导我进入已知类型解决方案,这将要求我包含一个具有目标类型的每个子类的数组(并且上帝知道有多少附加层)。
这听起来像是对DRY和SRP原则的极端违反,因为如果我每次添加一个子类,我都要绕过我的源代码寻找要更新的已知类型的列表(这是Shotgun Surgery anti -pattern,并且是该系统以前版本的最差特征之一)。
我已经看到了一种使用反射并获得已知类型列表的方法,但我猜它(我不在乎),所以我的问题是:
对于DRY和已知类型列表问题,对象树包含大量继承的类,处理DataContractSerialization的好方法是什么?
或者,如果有另一种类型安全的方法将对象序列化和反序列化为XML字符串,那么这可能是一个选项。
答案 0 :(得分: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
和程序集,您可以搜索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();
}