将一般 class 委派给特定 class 人员
Delegating general class to specific classes
我有以下接口:
public interface IModel
{
ModelTypes ModelType { get; } // ModelTypes is an enum
}
public interface IModelConverter<T>
{
byte[] ToBytes(T model);
}
此外,我有 3 个 IModel
的实现:ModelA
、ModelB
、ModelC
,以及以下 classes:
public class ModelAConverter : IModelConverter<ModelA>
public class ModelBConverter : IModelConverter<ModelB>
public class ModelCConverter : IModelConverter<ModelC>
我想使用 IModel
并用 ToBytes
方法转换它。显然,我不希望调用者知道转换器的每一个实现,所以我创建了 DelegatingConverter
class:
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
。
错误是:
Argument type ModelXConverter
is not assignable to parameter type
IModelConverter<IModel>
而且我知道这里的解决方案应该是在 IModelConverter
中对 T
使用协方差,所以 decleration 应该是:
public interface IModelConverter<out T>
我添加的时候出现如下错误:
Parameter must be input-safe. Invalid variance: The type parameter 'T'
must be contravariantly valid on IModelConverter.ToBytes(T). 'T' is
covariant.
有什么办法可以让它变得更好吗?我知道我可以让每个 ModelConverter
实现都实现 IModelConverter<IModel>
,但是我需要在每个实现的开头进行明显的转换。
And I know the solution here should be using covariance on T
in IModelConverter
不,不是真的。只有当任何 specific IModelConverter
可以被视为更 general 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
方法 - 但假设 model.ModelType
是正确的,那应该没问题。 (如果不是,异常可能是正确的行为。)
您可以显式地强制转换它以避免像
这样的错误
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 interface IModel
{
ModelTypes ModelType { get; } // ModelTypes is an enum
}
public interface IModelConverter<T>
{
byte[] ToBytes(T model);
}
此外,我有 3 个 IModel
的实现:ModelA
、ModelB
、ModelC
,以及以下 classes:
public class ModelAConverter : IModelConverter<ModelA>
public class ModelBConverter : IModelConverter<ModelB>
public class ModelCConverter : IModelConverter<ModelC>
我想使用 IModel
并用 ToBytes
方法转换它。显然,我不希望调用者知道转换器的每一个实现,所以我创建了 DelegatingConverter
class:
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
。
错误是:
Argument type
ModelXConverter
is not assignable to parameter typeIModelConverter<IModel>
而且我知道这里的解决方案应该是在 IModelConverter
中对 T
使用协方差,所以 decleration 应该是:
public interface IModelConverter<out T>
我添加的时候出现如下错误:
Parameter must be input-safe. Invalid variance: The type parameter 'T' must be contravariantly valid on IModelConverter.ToBytes(T). 'T' is covariant.
有什么办法可以让它变得更好吗?我知道我可以让每个 ModelConverter
实现都实现 IModelConverter<IModel>
,但是我需要在每个实现的开头进行明显的转换。
And I know the solution here should be using covariance on
T
inIModelConverter
不,不是真的。只有当任何 specific IModelConverter
可以被视为更 general 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
方法 - 但假设 model.ModelType
是正确的,那应该没问题。 (如果不是,异常可能是正确的行为。)
您可以显式地强制转换它以避免像
这样的错误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()}
};
}