c# - 将通用类委托(delegate)给特定类

标签 c# .net covariance contravariance

我有以下接口(interface):

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

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

另外,我有 3 个 IModel 的实现: ModelA , ModelB , ModelC ,以及以下类:

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

一切顺利,直到我将一些转换器添加到委托(delegate)字典,_modelConverters .

错误是:

Argument type ModelXConverter is not assignable to parameter type IModelConverter<IModel>

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

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

不,不是真的。只有在任何特定 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方法 - 但假设 model.ModelType是正确的,那应该没问题。 (如果不是,异常可能是正确的行为。)

关于c# - 将通用类委托(delegate)给特定类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29834144/

相关文章:

c# - 使用字典和泛型创建嵌套的 JSON 可序列化对象结构时,.NET 中的 C# 协方差存在问题

c# - 空检查在哪里?

c# - 为什么我不能将 DateTime[] 转换为 object[]?

c# - C# 泛型约束中的通配符

c# - 创建和使用协变和可变列表(或潜在的解决方法)

c# - 禁用 TreeView 中某些条目的可聚焦性

c# - 处理来自消息框的回复 C#

c# - 为什么 !DumpHeap -stat 中的对象总和与 !EEHeap -gc 不匹配?

c# - 在 IIS 上托管 WCF Web 服务时显式调用服务构造函数

c# - 如何在 C# 泛型中将子类转换为父类