5

我有一个最小的接口,并将处理其类实现此接口的对象集合。集合(连同它的相关功能)不关心这些对象的任何细节,除了它们的名称、将它们转换为 XML 的能力以及从 XML 解析它们的能力。

接口的未来实现将对集合的元素做更多的事情,并且显然会实现它们自己的 Parse 和 ToXml 方法(集合将使用它们在遇到这些项目时适当地解析这些项​​目)。

不幸的是,我无法在界面中列出静态 Parse 方法(我已阅读 三个 问题)。让 Parse 方法需要一个实例对我来说没有意义。有没有办法要求接口的所有实现都具有静态 Parse 方法?

public interface IFoo
{
  string Name { get; }

  string ToXml();

  static IFoo Parse(string xml); // Not allowed - any alternatives?
}
4

6 回答 6

5

你不能那样做。而且静态方法无论如何都不是多态的,所以它没有太多意义。

你在这里想要的是某种工厂模式。

于 2013-03-20T15:03:07.627 回答
2

假设Parse接受一个字符串并将其转换为一个完全填充的对象,那么一个Hydrate方法怎么样,比如:

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

或者稍微流利一下:

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

void Main() {
    IFoo f = new Foo().Hydrate(someXml);
}
于 2013-03-20T15:11:54.113 回答
1

我想到的唯一选择是在这里使用抽象类而不是接口。但是,无论如何您都无法覆盖子类中静态方法的行为。

您可以使用工厂模式实现一些类似的行为,并要求实现IFoo的类具有对该工厂的引用(可以通过构造函数注入将其注入其中):

public interface IFoo
{
    string Name { get; }

    string ToXml();

    IFooFactory FooFactory { get; }
}

public interface IFooFactory
{
    IFoo Parse(string xml);
}
于 2013-03-20T15:03:44.583 回答
1

我会将所有与序列化相关的方法提取到不同的接口中。请考虑以下示例:

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. */ }
于 2013-03-20T15:27:42.190 回答
0

也许这样?

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
}

即使上述可能是一个解决方案,我也会鼓励您改用抽象工厂和/或模板方法。请参阅模板方法模式。如果您不想在多个实现之间共享它,另一个选项可能是使用扩展方法。

于 2013-03-20T15:13:55.660 回答
0

从广义上讲,我知道(有时)使用扩展方法来处理这样的事情:

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

这就是实例的内容,让我们处理“静态”位:

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

和一个测试:

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

正如@Jim 提到的那样,在某些情况下您不想要Foo背部,在这种情况下您可能会使用类似的东西:

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

唉,当我们偏离“规范”时,我们现在必须告诉方法我们想要什么:

var aFoo = "some xml".Parse<Foo>();
Console.WriteLine(aFoo.ToXml());    
var aBar = "some xml".Parse<Bar>(s => new Bar(s));
Console.WriteLine(aBar.ToXml());    
于 2013-03-20T15:25:38.383 回答