c# - 使用奇怪的重复模板模式继承序列化

标签 c# design-patterns generics xml-serialization xml-deserialization

我有一个基类定义如下:

public abstract class XMLBackedObject<T> where T: XMLBackedObject<T>
{   
/// <summary>
/// Load the specified xml file and deserialize it.
/// </summary>
/// <param name='filePath'>
/// File path to load
/// </param>
public static T Load(string filePath)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
        using(FileStream stream = new FileStream(filePath, FileMode.Open))
        {
            return serializer.Deserialize(stream) as T;
        }
}

/// <summary>
/// Save this instance to the specified file path
/// </summary>
/// <param name='filePath'>
/// File path to save to.
/// </param>
public void Save(string filePath)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));
        using(FileStream stream = new FileStream(filePath, FileMode.Create))
        {
            serializer.Serialize(stream, this);
        }
}
}

类继承如下:

配置文件:

using UnityEngine;
using System.Collections.Generic;

    [System.Serializable]
    public class Config : XMLBackedObject<Config>
    {
        public Config()
        {
        }

        public string WordDirectoryPath;
        public string CommandDirectoryPath;
    }

命令.cs:

using UnityEngine;
using System.Collections.Generic;

[System.Serializable]
public abstract class Command : XMLBackedObject<Command>
{
    //The word that triggers this command
    public Word Word;
    //The command's target
    public List<Word> Targets;
    //Minimum number of targets for the command to be valid
    public int RequiredTargets;

    //Message to send when bad targets are supplied
    public string BadTargetString;
    //Message to send when no target is supplied
    public string noTargetString;


    public Command(Word word, List<Word> targets,int requiredTargets)
    {
        Targets = targets;
        this.Word = word;
        this.RequiredTargets = requiredTargets;
    }

    public Command()
    {
        Targets = new List<Word>(); 
    }

    /// <summary>
    /// Execute the command on the supplied targets
    /// </summary>
    /// <param name='targets'>
    /// Targets to process
    /// </param>
    public abstract void Execute(IEnumerable<Word> targets);
}

MenuNavigationCommand.cs:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class MenuChoiceCommand : Command {

    public MenuChoiceCommand()
    {
    }

    public MenuChoiceCommand(Word word, List<Word> targets, int requiredTargets) : base(word,targets,requiredTargets)
    {
    }

    public override void Execute (System.Collections.Generic.IEnumerable<Word> targets)
    {

    }
}

这是调用保存函数的代码:

public void BuildTestXMLFiles()
    {
        Config config = new Config();
        config.CommandDirectoryPath = "commdirpath";
        config.WordDirectoryPath = "wordirparth";
        config.Save (Application.dataPath + "/testconfig.xml");

        MenuChoiceCommand command = new MenuChoiceCommand(word,new List<Word>(),2);
        command.Targets.Add (word);
        command.Save (Application.dataPath + "/testcommand.xml");
    }

Config 的 Save 函数执行时没有任何问题,但是在 MenuNavigationCommand 上使用 Save 会给我这个错误:

InvalidOperationException: The type of the argument object 'MenuChoiceCommand' is not primitive.

我需要 MenuNavigationCommand 做的就是保存存在于它继承的 Command 类中的字段,而不是 MenuNavigationCommand 中的任何新字段。有什么办法吗?或者我应该只在每个使用不止一个继承级别的类上实现一个加载和保存方法?

编辑:添加了文件的完整来源。

最佳答案

MenuChoiceCommand继承Command , 它继承了 XMLBackedObject<Command> , 不是 XMLBackedObject<MenuChoiceCommand> .所以 Save 创建的序列化程序适用于类型 Command , 不是 MenuChoiceCommand ...你需要制作MenuChoiceCommand继承XMLBackedObject<MenuChoiceCommand>为此工作(但你将无法使其继承 Command ,因为 C# 不允许多重继承)。

对此使用奇怪的重复模板模式乍一看似乎是个好主意,但正如您所看到的,您很快就会遇到它的局限性。

无论如何,我不认为序列化逻辑应该是数据类本身的一部分;在具有通用方法的辅助类中执行此操作可能会更好:

public static class XmlHelper
{
    public static T Load<T>(string filePath)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using(FileStream stream = new FileStream(filePath, FileMode.Open))
        {
            return (T)serializer.Deserialize(stream);
        }
    }

    public static void Save<T>(T obj, string filePath)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using(FileStream stream = new FileStream(filePath, FileMode.Create))
        {
            serializer.Serialize(stream, obj);
        }
    }
}

关于c# - 使用奇怪的重复模板模式继承序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18300063/

相关文章:

c# - 将整个 Container.DataItem 行传递给代码隐藏

java - 可序列化集合的通用参数

java - 使用泛型时类型不兼容

c# - 如何动态创建包含点符号的 Lambda 表达式

c# - 使用 PDFSharp 打印 PDF

c# - 使用 HTTP Web 请求发送 HTTP header 以进行 NTLM 身份验证

java - 使用 Spring Boot 代替 DTO、Dao、Service 的设计模式?

wpf - WPF 应用程序可以进行依赖注入(inject)吗?

C#类设计: strategy pattern with some classes that have caching functionality?

java - 如何将项目添加到同一父类(super class)型的通用列表中?