C# 将一般类委托给特定类

C# 将一般类委托给特定类,c#,.net,covariance,contravariance,C#,.net,Covariance,Contravariance,我有以下接口: public interface IModel { ModelTypes ModelType { get; } // ModelTypes is an enum } public interface IModelConverter<T> { byte[] ToBytes(T model); } 我想取一个IModel并用ToBytes方法将其转换。显然,我不想让调用者知道转换器的每个实现,所以我创建了DelegatingConverter类: pu

我有以下接口:

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

public interface IModelConverter<T>
{
    byte[] ToBytes(T model);
}
我想取一个
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);
    }
}
公共类DelegatingConverter:IModelConverter
{
专用只读字典(modelConverters);;
公共DelegatingConverter()
{
_modelConverters=新字典
{
{ModelTypes.TypeA,new ModelAConverter()},//参数类型ModelAConverter不能分配给参数类型IModelConverter
{ModelTypes.TypeB,new ModelBConverter()},//参数类型ModelBConverter不能分配给参数类型IModelConverter
{ModelTypes.TypeC,new modelconverter()}//参数类型modelconverter不能分配给参数类型IModelConverter
};
}
公共字节[]ToBytes(IModel模型)
{
//代表团到了。。
返回_modelConverters[model.ModelType].ToBytes(model);
}
}
一切都很顺利,直到我将一些转换器添加到委派字典中,
\u modelConverters

错误是:

参数类型
ModelXConverter
不可分配给参数类型
IModelConverter

我知道这里的解决方案应该是在
IModelConverter
中使用
T
上的协方差,所以偏差应该是:

公共接口IModelConverter

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

参数必须是输入安全的。无效的差异:类型参数“T” 必须在IModelConverter.ToBytes(T)上反向有效是的 协变的

有没有办法让它变得更好?我知道我可以使每个
ModelConverter
实现实现
IModelConverter
,但是我需要在每个实现的开头进行一个明显的强制转换

我知道这里的解决方案应该是在
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);
    }
}
//这个类是通用的。。。
公共密封类DelegatingConverter:IModelConverter
T:IModel在哪里
{
专用只读IModelConverter原始转换器;
公共授权转换器(IModelConverter原始转换器)
{
this.originalConverter=originalConverter;
}
公共字节[]ToBytes(IModel模型)
{
返回原始转换器ToBytes((T)模型);
}
}
然后:

公共密封类KnownModelConverter:IModelConverter
{
专用静态只读字典
=新词典
{
{ModelTypes.TypeA,新的DelegatingConverter(新的ModelAConverter())},
{ModelTypes.TypeB,新的DelegatingConverter(新的ModelBConverter())},
{ModelTypes.TypeC,新的DelegatingConverter(新的modelconverter())},
};
公共字节[]ToBytes(IModel模型)
{
//代表团到了。。
返回_modelConverters[model.ModelType].ToBytes(model);
}
}

基本上,关键在于
DelegatingConverter
中的强制转换-您需要确保只将正确类型的实例传递给其
ToBytes
方法-但是假设
model.ModelType
是正确的,这应该是可以的。(如果不是,则异常可能是正确的行为。)

您可以显式键入cast,以避免出现如下错误

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()}
    };
}
public DelegatingConverter()
{
_modelConverters=新字典
{
{ModelTypes.TypeA,(IModelConverter)新modelConverter()},
{ModelTypes.TypeB,(IModelConverter)new ModelBConverter()},
{ModelTypes.TypeC,(IModelConverter)新modelconverter()}
};
}

一种稍微精简的方法是,只需使用一个静态的
转换器
类,其中包含多个重载的
ToBytes
,这些重载可以接受各种型号。现在,您只需执行
Converter.ToBytes(myModel)
@Asad:这假设调用者在编译时知道类型。为了使它在只显示一个
IModel
时工作,您需要基本上沿着这些行的代码-或者一个
开关或类似的东西。如果调用程序在编译时不知道类型,您可以只执行
Converter.ToBytes((动态)myModel)
,并且非常优雅地依赖于动态调度。@Asad:使用
dynamic
是我考虑建议的其他选项之一-在这一点上,它非常容易适应现有代码,并且OP仍然可以实现
IModelConverter
。Jon,如果向
DelegatingConverter
添加一个约束不是更好吗<代码>公共密封类DelegatingConverter:IModelConverter,其中T:IModel
?这将防止您在编译时犯一些错误,要么编译失败(如果类被密封),要么强制转换在执行时失败。转换器根本不是
IModelConverter
sNo,我不是在猜测。如果这些类实际实现了
IModelConverter
,那么编译器首先为什么会抱怨呢?您希望强制转换如何工作?@JonSkeet是100%正确的,我尝试了它,但出现了运行时错误。您的
ModelConverter
类是无状态的吗?
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);
    }
}
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()}
    };
}