2

我有一个定义如下的基类:

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

菜单导航命令.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)
    {

    }
}

这是调用 Save 函数的代码:

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 中的任何新字段。有没有办法做到这一点?或者我应该在每个使用多个继承级别的类上实现一个 Load 和 Save 方法?

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

4

1 回答 1

1

MenuChoiceCommand继承Command,继承XMLBackedObject<Command>,不继承XMLBackedObject<MenuChoiceCommand>。因此,由创建的序列化Save程序是用于 type Command,而不是MenuChoiceCommand......您需要 make MenuChoiceCommandinheritXMLBackedObject<MenuChoiceCommand>才能使其工作(但是您将无法使其 inherit 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);
        }
    }
}
于 2013-08-18T21:42:18.130 回答