如何覆盖子类中的静态类工厂方法
How to override static, factory-like method in subclasses
问题:
基class中的静态方法不能被覆盖,所以我不能编译这段代码(如果可以的话,我的设计就解决了):
public abstract class ParametersBase
{
public static abstract ParametersBase CreateDefault(); // THIS DOES NOT COMPILE!
}
public abstract class ParametersXml<T> where T : ParametersBase
{
public static T LoadOrDefault(string fname)
{
System.Threading.Thread.CurrentThread.CurrentCulture =
System.Globalization.CultureInfo.InvariantCulture;
T result;
var serializer = new XmlSerializer(typeof(T));
FileStream fs;
try
{
using (fs = new FileStream(fname, FileMode.Open, FileAccess.Read))
result = (T)serializer.Deserialize(fs);
}
catch (InvalidOperationException)
{
result = (T)typeof(T).GetMethod("CreateDefault").Invoke(null, new object[] { });
using (fs = new FileStream(fname, FileMode.Create, FileAccess.Read))
serializer.Serialize(fs, result);
}
return result;
}
}
上下文:
我正在尝试使用泛型在一组表示参数组的子classes 中实现简单的XML持久性:
- 每个
Parameter
subclass 都有一些在 subclass 之间变化的属性集;
- 每个 class 将有一个静态
LoadOrDefault
方法和一个实例 Save
方法;
- 持久性(xml 序列化和反序列化)的详细信息将封装在单个 class;
中
- 具有默认值的实例化将放在各自的 class.
中
我什至不确定这些应该是正确的合作,我的意思是,每个 ParameterBase
都需要 "wrapped" 由 ParametersXml<>
,而也许正确的事情是通过继承将持久性代码 封装在 基础 class 中...
这是一个好方法吗?我错过了什么吗?
只是为了详细说明评论中发生的事情。
将 static
方法标记为 abstract
会产生编译时错误。主要是因为你不能将一般意义上的多态应用于抽象方法(永远不会有虚方法调用)。
在此实例中需要的是不将方法标记为 static
。现在由此产生的问题是,不能确定可以获取T
的一个实例。然而,这可以通过进一步约束 T
来改变,使构造函数不带参数,方法是将 class 定义更改为:
public abstract class ParametersXml<T> where T : ParametersBase, new()
现在 catch
在 LoadOrDefault
中可以说:
result = new T().CreateDefault();
请注意,这也更加简洁,并且避免了反射和脏类型转换的使用。
编辑:
更进一步
正如@AlexeiLevenkov 所指出的——假设 CreateDefault
应该是 return 它自己类型的实例,并且无参数构造函数在其默认设置中设置 T
状态。甚至可以完全消除对 CreateDefault
的需要,只需将无参数构造函数用作 CreateDefault
,从而将 catch 处理程序中的行更改为:
result = new T();
问题:
基class中的静态方法不能被覆盖,所以我不能编译这段代码(如果可以的话,我的设计就解决了):
public abstract class ParametersBase
{
public static abstract ParametersBase CreateDefault(); // THIS DOES NOT COMPILE!
}
public abstract class ParametersXml<T> where T : ParametersBase
{
public static T LoadOrDefault(string fname)
{
System.Threading.Thread.CurrentThread.CurrentCulture =
System.Globalization.CultureInfo.InvariantCulture;
T result;
var serializer = new XmlSerializer(typeof(T));
FileStream fs;
try
{
using (fs = new FileStream(fname, FileMode.Open, FileAccess.Read))
result = (T)serializer.Deserialize(fs);
}
catch (InvalidOperationException)
{
result = (T)typeof(T).GetMethod("CreateDefault").Invoke(null, new object[] { });
using (fs = new FileStream(fname, FileMode.Create, FileAccess.Read))
serializer.Serialize(fs, result);
}
return result;
}
}
上下文:
我正在尝试使用泛型在一组表示参数组的子classes 中实现简单的XML持久性:
- 每个
Parameter
subclass 都有一些在 subclass 之间变化的属性集; - 每个 class 将有一个静态
LoadOrDefault
方法和一个实例Save
方法; - 持久性(xml 序列化和反序列化)的详细信息将封装在单个 class; 中
- 具有默认值的实例化将放在各自的 class. 中
我什至不确定这些应该是正确的合作,我的意思是,每个 ParameterBase
都需要 "wrapped" 由 ParametersXml<>
,而也许正确的事情是通过继承将持久性代码 封装在 基础 class 中...
这是一个好方法吗?我错过了什么吗?
只是为了详细说明评论中发生的事情。
将 static
方法标记为 abstract
会产生编译时错误。主要是因为你不能将一般意义上的多态应用于抽象方法(永远不会有虚方法调用)。
在此实例中需要的是不将方法标记为 static
。现在由此产生的问题是,不能确定可以获取T
的一个实例。然而,这可以通过进一步约束 T
来改变,使构造函数不带参数,方法是将 class 定义更改为:
public abstract class ParametersXml<T> where T : ParametersBase, new()
现在 catch
在 LoadOrDefault
中可以说:
result = new T().CreateDefault();
请注意,这也更加简洁,并且避免了反射和脏类型转换的使用。
编辑: 更进一步
正如@AlexeiLevenkov 所指出的——假设 CreateDefault
应该是 return 它自己类型的实例,并且无参数构造函数在其默认设置中设置 T
状态。甚至可以完全消除对 CreateDefault
的需要,只需将无参数构造函数用作 CreateDefault
,从而将 catch 处理程序中的行更改为:
result = new T();