我有一个最小的接口,并将处理其类实现此接口的对象的集合。该集合(及其相关功能)不关心这些对象的名称之外的任何细节,将它们转换为XML的能力,以及从XML解析它们的能力。
接口的未来实现将对集合的元素做更多的工作,并且显然会实现自己的Parse和ToXml方法(当遇到这些方法时,集合将使用它们来适当地解析这些项目。)
不幸的是,我无法在界面中列出静态Parse方法(我已阅读these three questions)。让Parse方法需要一个实例对我来说没有意义。有没有办法要求接口的所有实现都有静态Parse方法?
public interface IFoo
{
string Name { get; }
string ToXml();
static IFoo Parse(string xml); // Not allowed - any alternatives?
}
答案 0 :(得分:5)
你做不到。而静态方法无论如何都不是多态的,所以它没有多大意义。
你想要的是某种工厂模式。
答案 1 :(得分: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);
}
答案 2 :(得分:1)
我想到的唯一选择是在这里使用抽象类而不是接口。但是,无论如何,您将无法在子类中覆盖静态方法的行为。
您可以使用Factory模式实现某种类似的行为,并要求实现IFoo
的类具有对该Factory的引用(可以通过构造函数注入将其注入其中):
public interface IFoo
{
string Name { get; }
string ToXml();
IFooFactory FooFactory { get; }
}
public interface IFooFactory
{
IFoo Parse(string xml);
}
答案 3 :(得分: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. */ }
答案 4 :(得分: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
}
即使以上可能是一个解决方案,我也鼓励您使用抽象工厂和/或模板方法。请改为Template Method Pattern。如果您不想在多个实现中共享它,则另一个选项可能是使用Extension method。
答案 5 :(得分: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());