我有一个基类定义如下:
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/