【发布时间】:2021-04-03 01:12:45
【问题描述】:
我正在尝试编写一个可以在不同类型之间进行转换的简单库。使用 .Net Core 3.1。
这样做的目的是在继承自同一个基类的两个类之间进行转换。
public class SharedBaseClass {}
public class DestinationClass : SharedBaseClass {
public DestinationClass(){}
}
public class InputClass : SharedBaseClass {
public InputClass(){}
}
因此,我已经介绍了一个定义这种转换器的接口
public interface IConverter<out TU> where TU : SharedBaseClass
{
public TU Convert(SharedBaseClass input);
}
然后下面的类使用这个接口来执行转换
public class ConverterExecutor
{
private readonly Dictionary<Type, IConverter<SharedBaseClass>> _converters;
public ConverterExecutor(Dictionary<Type, IConverter<SharedBaseClass>> converters)
{
_converters = converters;
}
public IEnumerable<SharedBaseClass> ConvertMultiple(IEnumerable<SharedBaseClass> classesToConvert)
{
var converted = new List<SharedBaseClass>();
foreach(var toConvert in classesToConvert)
{
_converters.TryGetValue(toConvert.GetType(), out var converter);
if (converter != null) {
converted.Add(converter.Convert(toConvert));
continue;
}
converted.Add(toConvert);
}
return converted;
}
}
然后,客户端将简单地创建 IConverter 接口的实现来封装转换逻辑。从InputClass 到DestinationClass 的转换器示例是
public class DestinationConverter: IConverter<DestinationClass> {
public DestinationClass Convert(SharedBaseClass input) {
return new DestinationClass();
}
}
为了完成示例,我添加了一个简短的 main 方法来说明如何设置这些方法
public class Program
{
public static void Main()
{
var executor = new ConverterExecutor(new Dictionary<Type, IConverter<SharedBaseClass>>{
// various converters for various types added here
{typeof(InputClass), new DestinationConverter()}
});
var result = executor.ConvertMultiple(new List<SharedBaseClass>{new InputClass()});
Console.WriteLine(result.First());
}
}
这一切都有效,但是我对 IConverter 实现的 convert 方法的输入参数依赖于基类这一事实感到困扰。
public DestinationClass Convert(SharedBaseClass input)
为了解决这个问题,我尝试重新定义界面:
public interface IConverter<out TU, in T> where TU : SharedBaseClass where T: SharedBaseClass
{
public TU Convert(T input);
}
此重构在所涉及的类中运行良好,并在每个实现中为我提供了正确的类型,但是在 main 方法中出现编译错误,因为 DestinationConverter 类的签名不适合添加到字典中。我怀疑这是因为T: SharedBaseClass 参数已作为in 参数(逆变)添加到IConverter 接口上,但是将其保留为不变量以同样的方式失败。我怀疑它是否是协变的(使用输入参数不可能),编译器会允许这样做。我想我的抽象在某个地方弄错了,那么在这种情况下,什么是合适的解决方案?
public class Program
{
public static void Main()
{
var executor = new ConverterExecutor(new Dictionary<Type, IConverter<SharedBaseClass, SharedBaseClass>>{
// various converters for various types to be added here
{typeof(InputClass), new DestinationConverter()}
});
var result = executor.ConvertMultiple(new List<SharedBaseClass>{new InputClass()});
Console.WriteLine(result.First());
}
}
失败的完整重构示例:https://dotnetfiddle.net/vuDCiH
【问题讨论】:
-
使用模式匹配,忘掉这一切。
-
有关“in”参数和方差的一些想法,请参阅stackoverflow.com/questions/2876315/…
标签: c# .net .net-core covariance abstraction