我有以下界面:
public interface IModel
{
ModelTypes ModelType { get; } // ModelTypes is an enum
}
public interface IModelConverter<T>
{
byte[] ToBytes(T model);
}
另外,我有3个
IModel
的实现:ModelA
,ModelB
,ModelC
和以下类:public class ModelAConverter : IModelConverter<ModelA>
public class ModelBConverter : IModelConverter<ModelB>
public class ModelCConverter : IModelConverter<ModelC>
我想要一个
IModel
并使用ToBytes
方法将其转换。显然,我不想让调用者知道转换器的每个实现,因此我创建了DelegatingConverter
类:public class DelegatingConverter : IModelConverter<IModel>
{
private readonly Dictionary<ModelTypes, IModelConverter<IModel>> _modelConverters;
public DelegatingConverter()
{
_modelConverters = new Dictionary<ModelTypes, IModelConverter<IModel>>
{
{ModelTypes.TypeA, new ModelAConverter()}, // Argument type ModelAConverter is not assignable to parameter type IModelConverter<IModel>
{ModelTypes.TypeB, new ModelBConverter()}, // Argument type ModelBConverter is not assignable to parameter type IModelConverter<IModel>
{ModelTypes.TypeC, new ModelCConverter()} // Argument type ModelCConverter is not assignable to parameter type IModelConverter<IModel>
};
}
public byte[] ToBytes(IModel model)
{
// Here is the delegation..
return _modelConverters[model.ModelType].ToBytes(model);
}
}
一切顺利,直到我在委派词典
_modelConverters
中添加了一些转换器。错误是:
参数类型
ModelXConverter
不可分配给参数类型IModelConverter<IModel>
而且我知道这里的解决方案应该在
T
中的IModelConverter
上使用协方差,因此,清零应该是:public interface IModelConverter<out T>
当我添加它时,会发生以下错误:
参数必须是输入安全的。无效的方差:类型参数“ T”
必须在IModelConverter.ToBytes(T)上相反地有效。 'T'是
协变
有什么办法可以改善它?我知道我可以使每个
ModelConverter
实现实现为IModelConverter<IModel>
,但是然后我需要在每个实现的开始处进行明显的转换。 最佳答案
我知道这里的解决方案应该在T
中的IModelConverter
上使用协方差
不,不是。只有将任何特定的IModelConverter
视为更通用的IModelConverter
时,情况才会如此-事实并非如此。如果转换器仅知道如何将ModelB
转换为字节,那么您希望它对ModelC
做什么?
最简单的方法可能是编写更多类似以下内容的代码:
// This class is general...
public sealed class DelegatingConverter<T> : IModelConverter<IModel>
where T : IModel
{
private readonly IModelConverter<T> originalConverter;
public DelegatingConverter(IModelConverter<T> originalConverter)
{
this.originalConverter = originalConverter;
}
public byte[] ToBytes(IModel model)
{
return originalConverter.ToBytes((T) model);
}
}
然后:
public sealed class KnownModelConverter : IModelConverter<IModel>
{
private static readonly Dictionary<ModelTypes, IModelConverter<IModel>>
= new Dictionary<ModelTypes, IModelConverter<IModel>>
{
{ ModelTypes.TypeA, new DelegatingConverter<ModelA>(new ModelAConverter()) },
{ ModelTypes.TypeB, new DelegatingConverter<ModelB>(new ModelBConverter()) },
{ ModelTypes.TypeC, new DelegatingConverter<ModelC>(new ModelCConverter()) },
};
public byte[] ToBytes(IModel model)
{
// Here is the delegation..
return _modelConverters[model.ModelType].ToBytes(model);
}
}
基本上,键是
DelegatingConverter<T>
中的强制转换-您需要确保仅对ToBytes
方法使用正确类型的pass实例-但假设model.ModelType
是正确的,那应该没问题。 (如果不是,则异常可能是正确的行为。)