如何在子类中重载静态的,类似工厂的方法 [英] How to override static, factory-like method in subclasses

查看:139
本文介绍了如何在子类中重载静态的,类似工厂的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

来自基类的静态方法不能被重写,所以我无法编译这段代码(如果可以的话,我的设计将被解决):

p>

  public abstract class ParametersBase 
{
public static abstract ParametersBase CreateDefault(); //这不是编译器!
}

public abstract class ParametersXml< T>其中T:ParametersBase
{
public static T LoadOrDefault(string fname)
{
System.Threading.Thread.CurrentThread.CurrentCulture =
System.Globalization.CultureInfo。 InvariantCulture的;

结果;

var serializer = new XmlSerializer(typeof(T));
FileStream fs;

使用(fs = new FileStream(fname,FileMode.Open,FileAccess.Read))
结果=(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);
}

返回结果;


$ / code $ / pre

我试图使用泛型在一组子类中实现简单的XML持久性,这些子类表示沿着这些行的参数组:


  • 每个参数子类都有一些在子类中有所不同的属性集合;每个类都有一个静态的 LoadOrDefault 方法和一个实例 Save 方法;
  • 持久性细节(xml序列化和反序列化)将被封装在一个类中;
  • 具有默认值的实例化将放在每个类中。



我甚至不确定这些应该是正确的合作,我的意思是,每一个 ParameterBase 需要被 ParametersXml< ;> ,也许正确的做法是通过继承将基础类中的持久化代码封装在基类中。



<这是一个好方法吗?我是否缺少什么?

解决方案

只需详细说明评论中的内容即可。



static 方法标记为 abstract 给出编译时错误。主要是因为你不能将一般意义上的多态性应用于抽象方法(永远不会有虚拟方法调用)。



这个例子需要的是不要将方法标记为 static 。现在由此产生的问题是人们无法确定可以获得 T 的实例。然而,通过进一步限制 T 来让一个不带参数的构造函数通过将类定义更改为:

  public abstract class ParametersXml< T>其中T:ParametersBase,new()

现在在 catch LoadOrDefault 中可以这样说:

  result = new T()。CreateDefault(); 

注意这也是一个更清晰的方法,避免使用反射和脏类型转换。 / p>

编辑:
更进一步


正如@ AlexeiLevenkov - 假设 CreateDefault 应该返回自己类型的实例,并且无参数构造函数设置 T 处于默认状态。甚至可以完全删除对 CreateDefault 的需求,并简单地使用无参数构造函数作为 CreateDefault ,从而改变catch处理程序到:

  result = new T(); 


PROBLEM:

Static methods from a base class cannot be overriden, so I cannot compile this code (if I could, my design would be solved):

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

CONTEXT:

I am trying to use generics to implement simple XML persistence in a set of subclasses representing groups of parameters along these lines:

  • Each Parameter subclass has some set of properties that vary among subclasses;
  • Each class will have a static LoadOrDefault method, and an instance Save method;
  • Details of persistence (xml serialization and deserialization) will be encapsulated in a single class;
  • Instantiation with default values will be put in each respective class.

I'm not even sure these should be the correct collaborations, I mean, every ParameterBase needs to be "wrapped" by a ParametersXml<>, while perhaps the right thing would be to encapsulate persistence code inside the base class, via inheritance...

Is this a good approach? Am I missing something?

解决方案

Just to elaborate what went on in the comments.

Marking a static method as abstract gives a compile time error. Mainly due to the fact that you cannot apply polymorphism in the general sense to abstract methods (there would never be a virtual method call).

What is needed in this instance is to not mark the method as static. Now the problem that arises from this is that one cannot be sure that one can acquire an instance of T. However, this can be changed by further constraining T to have a constructor taking no arguments, by changing the class definition to:

public abstract class ParametersXml<T> where T : ParametersBase, new()

Now in the catch in LoadOrDefault it is possible to say:

result = new T().CreateDefault();

Notice how this is also a lot cleaner, and avoids both use of reflection and dirty type casts.

EDIT: Going even further

As pointed out by @AlexeiLevenkov - assuming that CreateDefault is supposed to return an instance of its own type, and that the parameterless constructor is setting up T in its default state. One could even completely remove the need for CreateDefault and simply use the parameterless constructor as CreateDefault, thus changing the line in the catch handler to:

result = new T();

这篇关于如何在子类中重载静态的,类似工厂的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆