首页 > 解决方案 > 复杂的泛型需要一些奇怪的铸件才能运行

问题描述

玩弄通用性,我建立了一个简单的社交网络模型,基于人和他们之间的关系。

所有这些都存储在一个容器中。

对于每个容器,我希望能够添加一些验证来检查一些特定的约束。

这是可能过于复杂的模型,但如前所述,我正在玩通用性,所以它是故意的:

public interface IContainer<TPerson, TRelation>
    where TRelation : IRelation<TPerson>
{
    IReadOnlyCollection<TPerson> Persons { get; }
    IReadOnlyCollection<TRelation> Relations { get; }
}

public class DefaultContainer<TPerson, TRelation>
    : IContainer<TPerson, TRelation>
    where TRelation : IRelation<TPerson>
{
    private readonly HashSet<TPerson> _persons;
    private readonly List<TRelation> _relations;

    //...
}

public class DummyValidator<TContainer, TPerson, TRelation>
    : IValidator<TContainer, TPerson, TRelation>
    where TContainer : IMutableContainer<TPerson, TRelation>
    where TRelation : IRelation<TPerson>
{
    public bool CanAddRelations(TContainer container, IEnumerable<TRelation> relations)
    {
        // guard clauses

        return true; // whatever
    }

    public bool CanCreate(IEnumerable<TPerson> persons, IEnumerable<TRelation> relations)
    {
        // guard clauses

        return CanAddRelations(new DefaultContainer<TPerson, TRelation>(), relations);
    }

    //...
}

[Fact]
public void Test()
{
    var sut = new DummyValidator<IContainer<int, IRelation<int>>, int, IRelation<int>>();
    sut.CanCreate(Enumerable.Empty<int>(), Enumerable.Empty<IRelation<int>>());
}

看一下类的CanCreate方法DummyValidator。它创建一个新容器(实现TContainer):

return CanAddRelations(new DefaultContainer<TPerson, TRelation>(), relations);

所以一切都应该没问题,据我所知。但是编译器抱怨说:

无法从“Alcuin.Graph.Containers.DefaultContainer”转换为“TContainer”

我的问题是:为什么它会抱怨这一点,即使每个通用参数都被描述并且总是等效的?

所以我尝试了一些明确的演员来调查:

return CanAddRelations((TContainer)new DefaultContainer<TPerson, TRelation>(), relations);

return CanAddRelations((IMutableContainer<TPerson, TRelation>)new DefaultContainer<TPerson, TRelation>(), relations);

都失败了,但是:

return CanAddRelations((TContainer)(IMutableContainer<TPerson, TRelation>)new DefaultContainer<TPerson, TRelation>(), relations);

编译并正确运行...

任何人都可以阐明这里发生的事情吗?我错过了一些明显的东西吗?我是否达到了 C# 通用引擎的极限?

标签: c#generics

解决方案


推荐阅读