1

我有一个只包含数据的类层次结构。例如:

class A 
{
    List<B> b { get; set; }
    C c { get; set; }
}

class B 
{ 
    int d { get; set; }
}

class C 
{
    List<int> e { get; set; }
}

类层次结构已准备好使用 XML 和 protobuf-net 进行序列化。它也存在于一个单独的库中,因为它需要由两个不同的应用程序使用。

现在我需要创建这个类层次结构的扩展版本,其中节点的数量和它们的关系是相同的,但每个节点中都可以有额外的数据、方法或属性。例如:

class AA : A
{
    int extra { get; set; }
}

class BB : B
{
    float extra { get; set; }
    void something();
}

class CC : C
{
    float extra { get; set; }
}

我在上面看到的一个问题是类之间的所有(继承的)引用仍然使用原始层次结构中的类型,即List<B>而不是List<BB>,所以我必须一直转换为新类型。更大的问题是我还需要能够从扩展的层次结构中序列化原始层次结构,当每个实例都是派生类型时,我无法做到这一点。

问题:有没有办法扩展一个完整的类层次结构,这样我就可以在某个地方拥有一个共享的纯数据对象模型,并且仍然能够在不丢失原始结构的情况下向外部添加更多信息和行为?

4

2 回答 2

3

我认为你可以使用泛型做你想做的事。至少对于防止铸造的解决方案。我仍在考虑如何从扩展的层次结构中序列化原始层次结构。

您的问题中的 B、BB、C 和 CC 类仍然相同。

首先是一个通用的 A 类:

class A<BType, CType> where BType: B where CType: C {
    List<BType> b { get; set;}
    CType c { get; set;}
}

然后是使用泛型 A 类的非泛型 A 类:

class A: A<B, C> {
}

以及也使用泛型 A 类的(非泛型)AA 类:

class AA: A<BB, CC> {
    int extra { get; set; }
}
于 2013-06-12T05:50:28.703 回答
0

我使用扩展对象设计模式的简化版本解决了这个问题。

步骤1)

首先,我创建了以下接口和抽象基类,分别供扩展和可扩展对象使用:

public interface IExtension 
{
    bool IsSerializable { get; }
}

public abstract class Extensible
{
    public static bool ShouldSerializeExtensions = true;

    public IExtension Extension { get; set; }

    public bool ShouldSerializeExtension()
    {
        return ShouldSerializeExtensions &&
               Extension != null &&
               Extension.IsSerializable;
    }
}

静态ShoulSerializeExtensions标志允许我暂时启用或禁用整个扩展的序列化,而该IsSerializable属性允许我创建根本不应该序列化的扩展。

注意:在序列化之前,我还需要提供我创建的所有具体扩展类型的列表。

第2步)

我让层次结构中的每个节点都继承自Extensible并为每个节点创建了扩展类:

public class A : Extensible
{
    List<B> b { get; set; }
    C c { get; set; }
}

public class B  : Extensible
{ 
    int d { get; set; }
}

public class C  : Extensible
{
    List<int> e { get; set; }
}

public class ExtensionA : IExtension
{
    bool IsSerializable { get { return true; } }
    int extra { get; set; }
}

public class ExtensionB : IExtension
{
    bool IsSerializable { get { return true; } }
    float extra { get; set; }
    void something();
}

public class ExtensionC : IExtension
{
    bool IsSerializable { get { return true; } }
    float extra { get; set; }
}

步骤 3)

我创建了一个工厂,以确保创建每个节点都附加了正确的扩展对象。

public static class Factory
{
    public static A CreateA()
    {
        var a = new A();
        a.Extension = new ExtensionA();
        return a;
    }

    ...
}

而且我还创建了扩展方法,使操作扩展更容易,而不必每次都转换为正确的类型。

public static class ExtensionUtils
{
    public static ExtensionA GetExtension(this A a)
    {
       return a.Extension as ExtensionA;
    }

    ...
}

例子)

一切就绪后,我可以创建一个扩展对象并更改其值,如下所示:

var a = Factory.CreateA();
a.GetExtension().extra = 20;

而且我可以通过Extensible.ShouldSerializeExtensions在序列化之前设置全局标志来序列化带有或不带有扩展名的层次结构。

于 2013-06-23T10:36:28.980 回答