从泛型静态方法解析泛型接口-是使用容器最简单的方法

本文关键字:最简单 方法 静态方法 泛型 泛型接口 | 更新日期: 2023-09-27 17:58:02

我有一个类似的代码:

    public static IEnumerable<T> ParseInput<T>(string input)
    {
        var xml = XElement.Parse(input);
// some more code here
        var parser = Container.Current.Resolve<IParser<T>>();
        return parser.Parse(xml);
    }

它包含一些常见的数据处理,然后调用解析器接口,这在不同的专业化之间非常不同。目前,我正在从容器中解析解析器接口,但我对从静态方法中使用容器有点不舒服。

除了这个和switch语句之外,还有更好或替代的方法来解决接口吗?

编辑:在我看来,这种混乱来自于将单元可测试OO编程(IoC,没有静态类)与函数编程结合起来的尝试。最干净的隔离线在哪里?可能会更早地解析解析器并将其传递到静态方法中。

从泛型静态方法解析泛型接口-是使用容器最简单的方法

编辑:我有点忘了你的意思。我很喜欢用容器装那种东西。Switch语句有点难看。因此,使用容器,可以通过以下方法使其更易于测试:

如果some code here很复杂,我倾向于确保它不是静态的,因为在使用依赖项注入时,对静态方法进行单元测试并不容易。如果它不复杂,你的代码对我来说很好:o)

选项1:不要使用静态方法。

相反,使用实例方法并将解析器注入其中

public static IEnumerable<T> ParseInput<T>(string input)
{
    var parser = Container.Current.Resolve<IXmlParser<T>>();
    return parser.ParseInput(input);
}
public class XmlParser : IXmlParser<T>
{
  private readonly IParser<T> _parser;
  public XmlParser(IParser<T> parser)
  {
     _parser= parser;
  }
  public IEnumerable<T> ParseInput(string input)
  {
      var xml = XElement.Parse(input);
      // some more code here
      return _parser.Parse(xml);
  }
}

选项2:将容器解析器与字符串输入一起传入。尽管这样做,选项3会更好。

public static IEnumerable<T> ParseInput<T>(string input, IObjectResolver resolver)
{
    var xml = XElement.Parse(input);
    // some more code here
    var parser = resolver.Resolve<IParser<T>>();
    return parser.Parse(xml);
}

选项3:传入已解析的解析器(此想法归功于Mark Seemann)

public static IEnumerable<T> ParseInput<T>(string input, IParser<T> parser)
{
    var xml = XElement.Parse(input);
    // some more code here
    return parser.Parse(xml);
}

大家一致认为应该首先解析解析器并将其传递到静态方法中。假设您已经知道正在解析的T,那么这似乎是一个不错的方法。它只是将获取解析器实例的责任推到一个级别,即调用ParseInput的类中。

我想这意味着你会有这样的代码:

var orderParser = new OrderParser();
var orders = InputParser.ParseInput(input, orderParser);

同样,这假设您知道所需的T(在本例中为Order)。如果您对事物进行一般性的解析,您将不知道T,因此也不会知道OrderParser是您应该使用的类。在这种情况下,您将面临同样的问题:您仍然需要使用switch语句或容器来抽象各种IParser<T>实现。

通用解析

如果是这种情况,您可以将实例方法与解析器工厂结合起来,以避免直接从消费类引用容器:

public class InputParser
{
    private readonly IParserFactory _parserFactory;
    public InputParser(IParserFactory parserFactory)
    {
        _parserFactory = parserFactory;
    }
    public IEnumerable<T> ParseInput<T>(string input)
    {
        var xml = XElement.Parse(input);
        // some more code here
        var parser = _parserFactory.CreateParser<T>();
        return parser.Parse(xml);
    }
}

IParserFactory的实现可以处理与容器的通信:

public sealed class ResolvedParserFactory : IParserFactory
{
    private readonly IContainer _container;
    public ResolvedParserFactory(IContainer container)
    {
        _container = container;
    }
    public IParser<T> CreateParser<T>()
    {
        return _container.Resolve<IParser<T>>();
    }
}

某些容器(如Autofac)可能会为您生成此工厂,或者提供其他方法将工厂类与直接引用容器解耦。

非通用解析

如果调用ParseInput的代码真的知道要解析哪个T,比如上面的OrderParser,那么就不需要工厂的复杂性。在这种情况下,我有一些改进API的建议。

CCD_ 13是在CCD_。您还可以将XML解析与其他代码和T解析解耦:

public static IEnumerable<T> ParseInput(this IParser<T> parser, XElement input)
{
    // some more code here
    return parser.Parse(input);
}
public static IEnumerable<T> ParseInput(this IParser<T> parser, string input)
{
    return parser.ParseInput(XElement.Parse(input));
}