将通用类委派给特定的类

时间:2015-04-23 20:55:29

标签: c# .net covariance contravariance

我有以下界面:

public interface IModel
{
    ModelTypes ModelType { get; } // ModelTypes is an enum
}

public interface IModelConverter<T>
{
    byte[] ToBytes(T model);
}

此外,我有IModel的3个实现:ModelAModelBModelC以及以下类:

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>

添加时,会出现以下错误:

  

参数必须是输入安全的。方差无效:类型参数&#39; T&#39;   必须在IModelConverter.ToBytes(T)上违反有效。 &#39; T&#39;是   协变。

有没有办法让它变得更好?我知道我可以制作每个ModelConverter实现工具IModelConverter<IModel>,但是在每次实现开始时我需要一个明显的演员。

2 个答案:

答案 0 :(得分:7)

  

我知道这里的解决方案应该在SELECT (p OR q OR r) AND (x OR y OR Z) AND (...)

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是正确的,那么应该没事。 (如果不是,一个例外可能是正确的行为。)

答案 1 :(得分:-1)

您可以明确键入强制转换以避免错误,如

public DelegatingConverter()
{
    _modelConverters = new Dictionary<ModelTypes, IModelConverter<IModel>>
    {
        {ModelTypes.TypeA, (IModelConverter<IModel>)new ModelAConverter()},
        {ModelTypes.TypeB, (IModelConverter<IModel>)new ModelBConverter()},
        {ModelTypes.TypeC, (IModelConverter<IModel>)new ModelCConverter()}
    };
}