从泛型静态方法解析泛型接口-是使用容器最简单的方法
本文关键字:最简单 方法 静态方法 泛型 泛型接口 | 更新日期: 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));
}