我正在编写一个允许用户运行测试的应用程序。测试由许多不同的对象组成,例如配置,温度和基准。设置等在xml之间来回保存。我在代码中传递了不同的XElements,因此我可以针对不同的情况以不同方式构建最终的xml文档。我希望做这样的事情:
public abstract class BaseClass<T>
{
abstract static XElement Save(List<T>);
abstract static List<T> Load(XElement structure);
}
public class Configuration : BaseClass<Configuration>
{
public string Property1 { get; set; }
public string Property2 { get; set; }
//etc...
public static XElement Save(List<Configuration>)
{
XElement xRoot = new XElement("Root");
//etc...
return xRoot;
}
public static List<Configuration> Load(XElement structure)
{
List<BaseClass> list = new List<BaseClass>();
//etc...
return list;
}
}
public class Temperature : BaseClass<Temperature>
{
public float Value { get; set; }
public static XElement Save(List<Temperature>)
{
//save
}
public static List<Temperature> Load(XElement structure)
{
//load
}
}
[编辑]:修改问题(更改上述职能的签名)[/ EDIT]
当然,我实际上不允许覆盖BaseClass的静态方法。解决这个问题的最佳方法是什么?我希望以下内容尽可能有效:
List<Temperature> mTemps = Temperature.Load(element);
List<Configuration> mConfigs = Configuration.Load(element);
Temperature.Save(mTemps);
Configuration.Save(mConfigs);
[编辑]更改了[/ EDIT]
上方的预期用法代码我能想到的唯一解决方案是以下,这是不可接受的:
public class File
{
public static XElement Save(List<Temperature> temps)
{
//save temp.Value
}
public static XElement Save(List<Configuration> configs)
{
//save config.Property1
//save config.Property2
}
//etc...
}
答案 0 :(得分:3)
静态方法不是类实例的一部分。无论如何,压倒它们都没有任何意义。他们无法访问他们恰好是其成员的实例的任何非静态部分。
这是一种策略模式场景,例如你可以只有一个静态负载&amp;保存检查传递给它们的对象类型的方法,并采取相应的措施。但是,这是另一种稍微更聪明的方法,它使用泛型类型来创建原型并调用其方法,允许您将逻辑保留在每个派生对象类型中。
(再次修改)
这是另一个裂缝,与我原来的建议一致。我实际测试了它并且它可以工作,所以我认为这是你能做的最好的事情来获得你正在寻找的所有功能(除了测试类型和有条件地调用代码)。您仍然需要传递Load
的类型,否则,运行时将不知道预期返回什么类型。但Save
普遍适用。并且子类实现是强类型的。
这只是使用列表中的第一个对象作为其原型,足够简单。
public interface IBaseObject
{
XmlElement Save(IEnumerable<IBaseObject> list);
IEnumerable<IBaseObject> Load(XmlElement element);
}
public interface IBaseObject<T> where T: IBaseObject
{
XmlElement Save(IEnumerable<T> list);
IEnumerable<T> Load(XmlElement element);
}
public class Temperature : IBaseObject<Temperature>, IBaseObject
{
public XmlElement Save(IEnumerable<Temperature> list)
{
throw new NotImplementedException("Save in Temperature was called");
}
public IEnumerable<Temperature> Load(XmlElement element)
{
throw new NotImplementedException("Load in Temperature was called");
}
// must implement the nongeneric interface explicitly as well
XmlElement IBaseObject.Save(IEnumerable<IBaseObject> list)
{
return Save((IEnumerable<Temperature>)list);
}
IEnumerable<IBaseObject> IBaseObject.Load(XmlElement element)
{
return Load(element);
}
}
// or whatever class you want your static methods living in
public class BaseObjectFile
{
public static XmlElement Save(IEnumerable<IBaseObject> list)
{
IBaseObject obj = list.DefaultIfEmpty(null).First(); // linq
return obj==null ? null : obj.Save(list);
}
public static IEnumerable<IBaseObject> Load<T>(XmlElement element)
where T: IBaseObject, new()
{
IBaseObject proto = new T();
return proto.Load(element);
}
}
(原始编辑)
这有一个问题,你必须使用类型调用静态方法,例如
BaseClass<Temperature>.Load()
对于Save方法有一种解决方法,但是你想要的部分内容是不可能的。 Load方法无法知道要返回的列表类型,因为它的唯一参数没有关于返回类型的信息。因此,它不可能决定创建哪种类型作为原型。所以无论如何,如果你想使用常见的Load方法,你必须传递类似上面语法的类型。
对于Save方法,您可以使用反射在静态方法中创建原型,方法是从第一个元素获取类型,然后从原型中调用Save方法。因此,如果您只需要根据需要使用Save方法,那么就有可能。
但最终,我认为做这样的事情要简单得多:
public static XElement Save(List<IBaseClass> list)
{
if (list is Temperature) {
// do temperature code
} else if (list is SomethingElse) {
// do something else
}
}
无论如何 - 就像我说它需要反射才能使Save方法以这种方式工作。我只是使用简单的方法。
(删除原始错误代码)
答案 1 :(得分:1)
如果你真的不关心它保存的格式,你可以自由使用序列化(内部使用反射)。
string SerialiseToString<T>(T source)
{
using (StringWriter sw = new StringWriter() && XmlSerializer xml = new XmlSerializer(typeof(OrderedItem)))
{
xml.Serializer(sw, source);
return sw.ToString();
}
}
如果要将其合并到XML文件的更大部分中,最简单的方法是解析此输出并将其添加到您的输出中。或者,您可以自己反映这些属性。
答案 2 :(得分:1)
如果共享部分相同,您可以将其放在BaseClass
:
public static XElement Save(IEnumerable<BaseClass> list)
{
var root = new XElement("root");
foreach (var item in list)
{
item.Save(root);
}
return root;
}
这里,Save(XElement)
是一个虚方法,每种类型都实现它。
显然,你无法通过加载来实现这一点,你要么必须知道你正在加载什么类型,要么找到一些方法来找出你正在加载的类型。