如何解决这个C#多态问题?

时间:2010-11-25 01:19:13

标签: c# .net class polymorphism

我有一个基类SpecialClass。许多其他类继承自它,如WriteSpecialClassReadSpecialClass。在将这些类转换为基类之后,将对这些类的实例进行序列化和反序列化。因此,我有很多这样的重复代码(用于序列化):

SpecialClass sc = null;

if (type.DisplayName == "Read") {
    sc = new ReadSpecialClass();
} else if (type.DisplayName == "Write") {
    sc = new WriteSpecialClass();
} else
    throw new NotSupportedException("Type not supported");

String xml = SerializeToXML(sc);

..和反序列化:

SpecialClass sc = null;

sc = (SpecialClass)DeserializeFromXML(xml);

switch (someVariableThatDicatesTypeOfSpecialClass) {
    case "Read":
        sc = (ReadSpecialClass)sc;
        break;
    case "Write":
        sc = (WriteSpecialClass)sc;
        break;
}

另一个重要的信息:SpecialClass定义了一堆抽象方法,每个从中继承的类都需要实现。从它继承的所有类都符合方法,但返回不同的东西,所以每个类都不一样。

如果需要,我可以发布序列化或反序列化方法。

我想尝试简化这一点,这样我就不必指定每个SpecialClass派生类(如ReadSpecialClass)。有没有办法做到这一点?我能想到的唯一方法是打鸭。谢谢你的帮助,

5 个答案:

答案 0 :(得分:3)

您是否考虑过SpecialClass中的serialize()方法?这样,如果有一些特殊注意事项,您可以覆盖base.serialize方法并处理任何独特需求。通过这种方式,它已经知道它是什么,并且条件不是必需的。

另一件需要考虑的事情可能是具有立面图案的辅助类。然后你可以有一个名为“public SpecialClass DeserializeSpecialClass()”的方法。然后,您可以将其转换为目标,而不是在反序列化器中转换类型。如果你发现你做了太多的转换,那么可以考虑将抽象方法添加到将在派生类中实现的基类。

希望这有帮助。

答案 1 :(得分:2)

对于序列化,您可以使用某种查找:

public class SpecialClass
{
    private static Dictionary<string, Func<SpecialClass>> factories =
        new Dictionary<string, Func<SpecialClass>>();

    static SpecialClass()
    {
        factories["Read"] = () => new ReadSpecialClass();
        factories["Write"] = () => new WriteSpecialClass();
    }

    public static SpecialClass CreateByName(string name)
    {
        Func<SpecialClass> factory;

        if (!factories.TryGetValue(name))
            throw new ArgumentException("name", "\"" name +
                "\" is not a recognized subclass of SpecialClass.");

        return factory();
    }
}

对于反序列化,这两行:

sc = (ReadSpecialClass)sc;
sc = (WriteSpecialClass)sc;

不执行实际转换。如果sc引用的对象不是合适的类型,他们唯一要做的就是抛出异常。你在这里做的几乎与:

相同
object a = "foo";
a = (string)a;

当然,演员会成功。但它不会以任何方式修改a指向的对象。它真正做的就是验证这个对象已经是一个字符串。

答案 2 :(得分:0)

if (sc is WriteSpecialClass)
{
    sc = (WriteSpecialClass) sc;
}
 else if (sc is ReadSpecialClass)
{
    sc = (ReadSpecialClass) sc;
}
else
{
    throw new NotSupportetException("Type not Supportet");
}

答案 3 :(得分:0)

如果您不关心性能,可以使用反射初始化名称中包含该类型名称的类型。

SerializeToXML()将基类SpecialClass作为参数,因此不应区分派生类ReadSpecialClassWriteSpecialClass之间的差异。为什么不将SerializeToXML()作为基类的实例方法?

答案 4 :(得分:0)

规则1. /您的派生类应负责自行序列化和反序列化,因为它们应该是唯一熟悉XML文档中存储的附加数据的人。

所以从ploymorphic的角度来看(注意你上面的代码不是多态的)你会做类似的事情

public class SpecialClass
{
  public virtual XElement SerializeToXML()
  {
    // Base impl
  }
}

public class YourDerivedClasses
{
  public override XElement SerializeToXML()
  {
    //derived implementation 
  }
}

非常直接。但是你遇到的问题不是序列化或多态行为,而是XML中正确类型的实例化。

解决该问题的一种方法是在XML文档中使用一些键来指定保存它的类型,并注册一个负责构造由该键索引的派生类型的工厂(属性适用于那种注册) ),一旦构造派生类型,用它来反序列化xml。

注意,您的工厂也可以是Base类的静态方法。

类似的东西,(当然未经测试)......

public class SpecialClass
{
  ***snip
  public static IEnumerable<SpecialClass> GetAllClasses(XElement xml)
  {
    IDictionary keyedtypes = GetKeyedTypesDictUsingReflection() // the registered factories
    foreach(var x in xml.Elements("YourClassesNode"))
    {
      string key = //get key from xml
      yield return keyedTypes[key].DeserializeFromXML(x);
    }
  }
}