繁体   English   中英

我该如何解决C#多态性问题?

[英]How can I solve this C# polymorphism problem?

我有一个基类, 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 )。 有什么办法吗? 我能想到的唯一方法就是打字。 谢谢你的帮助,

您是否考虑过SpecialClass中的serialize()方法? 这样,如果有一些特殊的考虑,您可以覆盖base.serialize方法并照顾任何独特的需求。 通过这种方式,它已经知道它是什么,而没有条件。

要考虑的另一件事可能是带有外观模式的帮助程序类。 然后,您可以使用一个称为“ public SpecialClass DeserializeSpecialClass()”的方法。 然后,可以将其强制转换为目标,而不是将其转换为反序列化器。 如果发现您进行了过多的转换,则可以考虑将抽象方法添加到将在派生类中实现的基类。

希望这可以帮助。

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

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指向的对象。 它真正要做的就是验证该对象已经是一个字符串。

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

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

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

规则1. /您的派生类应该负责自己的序列化和反序列化,因为它们应该是唯一了解XML Doc中存储的其他数据的类。

因此,从多态性的角度来看(请注意,上面的代码不是多态的),您将执行以下操作

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);
    }
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM