简体   繁体   中英

How to override static, factory-like method in subclasses

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM