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()}
};
}