我有以下界面:

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

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


另外,我有3个IModel的实现: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>

当我添加它时,会发生以下错误:


  参数必须是输入安全的。无效的方差:类型参数“ 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是正确的,那应该没问题。 (如果不是,则异常可能是正确的行为。)

10-06 08:41