6

I've got a minimal interface, and will be dealing with a collection of objects whose classes implement this interface. The collection (along with its associated functionality) doesn't care about any of the details of these objects beyond their name, the ability to convert them to XML, and the ability to parse them from XML.

Future implementations of the interface will do a lot more with the elements of the collection, and will obviously implement their own Parse and ToXml methods (which will be used by the collection to parse these items appropriately when encountered).

Unfortunately, I am unable to list a static Parse method in the interface (I've read these three questions). It doesn't make sense to me to have a Parse method require an instance. Is there any way to require that all implementations of the interface have a static Parse method?

public interface IFoo
{
  string Name { get; }

  string ToXml();

  static IFoo Parse(string xml); // Not allowed - any alternatives?
}
Community
  • 1
  • 1
yoozer8
  • 7,361
  • 7
  • 58
  • 93
  • Why do you want it to be a static implementation? Static is meant to be a shared method between different implementations (without dependencies to the current object, only other statics) but an interface should tell a derrived class that something needs to be implemented. I think "static" is not the thing you want here... – Beachwalker Mar 20 '13 at 15:17
  • Each class that implements this interface will need to parse instances from XML, but each will parse very differently. The parsing itself is unique to a particular class. – yoozer8 Mar 20 '13 at 16:42
  • ...so "static" is imho not the thing you want for the Parse method – Beachwalker Mar 21 '13 at 13:28
  • I have a similar problem. Class A must create objects of unknown type from a string. I think a generic class should work: `public class A { ... }`. Class A will simply expect T to have a static Parse method and throw exceptions if not. – Bitterblue Nov 24 '21 at 21:41

6 Answers6

6

You can't do that. And static methods aren't polymorphic anyway, so it wouldn't make too much sense.

What you want here is some kind of factory pattern.

spender
  • 117,338
  • 33
  • 229
  • 351
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
2

Assuming Parse takes a string and turns it into a fully-populated object, how about a Hydrate method instead, like:

interface IFoo {
    string Name { get; set; }
    int Age { get; set; }
    void Hydrate(string xml);
}

class Foo : IFoo {
    public string Name { get; set; }
    public int Age { get; set; }

    public void Hydrate(string xml) {
        var xmlReader = ...etc...;
        Name = xmlReader.Read(...whatever...);
        ...etc...;
        Age = xmlReader.Read(...whatever...);
    }
}

void Main() {
    IFoo f = new Foo();
    f.Hydrate(someXml);
}

Or Fluent it up a bit:

public IFoo Hydrate(string xml) {
    // do the same stuff
    return this;
}

void Main() {
    IFoo f = new Foo().Hydrate(someXml);
}
Joe Enos
  • 39,478
  • 11
  • 80
  • 136
1

The only alternative that comes to my mind is to use an abstract class instead of an interface here. However you won't be able to override static method's behaviour in child classes anyway.

You can achieve somewhat similar behaviour using Factory pattern and requiring classes implementing IFoo to have a reference to that Factory (which can be injected in them via constructor injection):

public interface IFoo
{
    string Name { get; }

    string ToXml();

    IFooFactory FooFactory { get; }
}

public interface IFooFactory
{
    IFoo Parse(string xml);
}
Alexander Tsvetkov
  • 1,649
  • 14
  • 24
  • I've considered that, but overriding in child classes is exactly what we need. – yoozer8 Mar 20 '13 at 15:04
  • @Jim as you don't use an instance to call a static method it doesn't make sense to override them, just write them in each class that needs it. – wRAR Mar 20 '13 at 15:08
  • @Jim: And that doesn't work with static methods anyway. You can't override a static method. – Daniel Hilgarth Mar 20 '13 at 15:08
  • @wRAR That was our plan, but most of the implementing classes will not be written by us. Is there any way to ensure that each of them *will have* a static Parse method? Or do we just have to trust whoever implements the class to do it? – yoozer8 Mar 20 '13 at 15:10
  • What about requiring them to contain a factory class providing a way of creating an instance of 'IFoo' from XML? I've updated my answer with such a solution. – Alexander Tsvetkov Mar 20 '13 at 15:17
1

I would extract all serialization-related methods into a different interface. Please consider the following example:

public interface IFoo
{
    string Name { get; }
    IFooSerializer GetSerializer(string format);
}

public enum FooSerializerFormat { Xml, Json };

public interface IFooSerializer
{
    string Serialize(IFoo foo);
    IFoo Deserialize(string xml);
}

public class Foo : IFoo
{
    public string Name { get; }

    public IFooSerializer GetSerializer(FooSerializerFormat format)
    {
        case FooSerializerFormat.Xml:
            return new FooXmlSerializer();

        case FooSerializerFormat.Json:
            return new FooJsonSerializer();
    }
}

public class FooXmlSerializer : IFooSerializer { /* Code omitted. */ }
public class FooJsonSerializer : IFooSerializer { /* Code omitted. */ }
npclaudiu
  • 2,401
  • 1
  • 18
  • 19
0

Maybe this way?

public interface IFoo
{
  string Name { get; }

  string ToXml();

  IFoo Parse(string xml);
}

public abstract class AFoo : IFoo
{
  public string Name { get; set; }

  public string ToXml() { };

  public IFoo Parse(string xml) { return AFoo.StaticParse(xml); };

  public static IFoo StaticParse(string xml) { };  // implement one here
}

Even if the above could be a solution I would encourage you to use the abstact factory and/or template method instead. See Template Method Pattern instead. Another Option might be the usage of an Extension method if you wan't to share it among several implementations.

Beachwalker
  • 7,685
  • 6
  • 52
  • 94
0

Broadly speaking, I have been known (on occasion) to use Extension methods for stuff like this:

public interface IFoo
{
    string Name {get;}
    string ToXml();    
}

public class Foo : IFoo
{
    public Foo(string name)
    {
        Name = name;
    }
    public string Name {get; private set;}
    public string ToXml()
    {
        return "<derp/>";
    }
}

So that's the instance stuff, let's handle the "static" bit:

public static class FooExts
{
    public static IFoo Parse(this string xml)
    {
        return new Foo("derp");
    }
}

And a test:

void Main()
{
    var aFoo = "some xml".Parse();
    Console.WriteLine(aFoo.ToXml());
}

As @Jim mentions, there is the case where you don't want a Foo back, in which case you might use something like:

public static T Parse<T>(
    this string xml, 
    Func<string, IFoo> useMeUseMe = null) 
    where T:IFoo
{
    if(useMeUseMe == null)
        useMeUseMe = (x => new Foo(x));
    return (T)useMeUseMe("derp");
}

Alas, we must now tell the method what we want when we deviate from the "norm":

var aFoo = "some xml".Parse<Foo>();
Console.WriteLine(aFoo.ToXml());    
var aBar = "some xml".Parse<Bar>(s => new Bar(s));
Console.WriteLine(aBar.ToXml());    
JerKimball
  • 16,584
  • 3
  • 43
  • 55