【问题标题】:Switching on type with a generic return type使用通用返回类型打开类型
【发布时间】:2018-03-27 03:21:25
【问题描述】:

我正在努力通过编写一些可以为我创建属性的助手来使 EF 更容易进行单元测试。我有几个支持字段

private Mock<DbSet<Workflow>> mockedWorkFlows;
private Mock<DbSet<WorkflowError>> mockedWorkFlowErrors;

我想要一个通用函数能够使用以下函数返回正确的支持字段

public Mock<DbSet<T>> Mocked<T>(T t) where T : class
{
   if ( (object)t is Workflow)
   {
       return mockedWorkFlows; //cannot Workflow to T
    }
}

我希望根据传递的类型返回几个私有支持字段。

但是,即使我添加了Workflow 的类约束,我也会遇到同样的错误。

我也尝试打开t's 类型,但也没有运气。除了对象之外,几个支持字段的类型不共享一个共同的祖先。我正在尝试做的事情可能吗?

【问题讨论】:

  • 我看不出这种方法有什么意义。创建一个 mock 需要 1 行代码,如果你想设置 mock,你必须单独设置每个 mock,所以你为什么不为某些类型的 mock 创建一个工厂。
  • 从 EF 上下文中模拟 IDbSet 不止一行代码。我有一个流利的接口来分配数据,但是你必须在某个地方公开支持字段,因为当你监视时,这就是实际调用的内容。我只想要一个更小的 API,而不是为上下文的所有 IDbSet 属性使用 WorkflowsMo​​cked、WorkflowErrorsMocked 等。
  • 您是否考虑过模拟SqlConnection,而不是模拟DbSet,例如,使用Effort 框架? github.com/tamasflamich/effort
  • @BenCottrell 不,我没有看到 Effort,但就测试而言,没有数据库,无论如何,任何 EF 调用都会被模拟。这个问题实际上与 EF 或 mocking 没有直接关系。我只想让返回类型本质上取决于泛型函数的类型参数。

标签: c# generics c#-7.0


【解决方案1】:

可能会严重滥用 C#7 的 switch 来实现你想要的,方法是打开一个不相关的值并使用 var 模式和 when 守卫:

public Mock<DbSet<T>> Mocked<T>() where T : class
{
    switch(true)
    {
        case var _ when typeof(T) == typeof(Workflow):
            return ...
        case var _ when typeof(T) == typeof(WorkflowError):
            return ...
        default:
            return null;
    }
}

能够匹配switch 语句中的类型是一个非常常见的请求。在 github 上的官方语言存储库中有改进 C# 的建议(请参阅Proposal: switch on System.Type 和 pProposal: Pattern match via generic constraint)。随着更多的模式匹配功能被添加到 C# (currently, set for "a 7.X release") 中,我们可能会为这个功能获得更好的语法。

【讨论】:

    【解决方案2】:

    如果我正确理解您的意图 - 您可以这样做:

    // no need to pass instance of T - why?
    public Mock<DbSet<T>> Mocked<T>() where T : class
    {
        if (typeof(T) == typeof(Workflow)) {
            // first cast to object, then to return type to avoid compile error
            // compiler does not know mockedWorkFlows is Mock<DbSet<T>>, but you
            // know it already, because you checked type 'T'
            return (Mock<DbSet<T>>) (object) mockedWorkFlows; //cannot Workflow to T
        }
        // etc
        return null;
    }
    

    这是否是好主意是另一回事。

    【讨论】:

    • 这就是我要找的。我试图为 C#7 使用 switch on 类型的流畅性,但这最终是我想要的(尽管我现在遇到了一个不同的错误!:))
    猜你喜欢
    • 2019-04-25
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    相关资源
    最近更新 更多