尝试将 class 类型约束与特定接口的类型约束结合使用时出现问题

Issue trying to combine class type constraint with type constraint for specific interface

我正在尝试为许多“引擎”编写单元测试。每种引擎类型都有不同的“配置”,但在它们的实例化方式、其他参数以及模拟如何全部需要挂在一起方面存在明显的重叠。为了解决这个问题,我有一个通用的测试助手 class 但我正在努力让类型约束按我需要的方式工作。

以下是一个简化的例子,希望能说明问题:

//using Moq;

public interface IGetFooableConfig
{
    int GetFoo();
    // + other things out of scope for this question
}

public interface IFoo1Config : IGetFooableConfig 
{
    // + other things out of scope for this question
}

public class Foo1Config : IFoo1Config
{
    public int GetFoo() { return 1; }
    // + other things out of scope for this question
}

public interface IFoo2Config : IGetFooableConfig
{
    // + other things out of scope for this question
}

public class Foo2Config : IFoo2Config
{
    public int GetFoo() { return 2; }
    // + other things out of scope for this question
}

public abstract class TestBuilder<GetFooableConfigInterface>
    where GetFooableConfigInterface : IGetFooableConfig, class
{
    Mock<GetFooableConfigInterface> configMock = new Mock<GetFooableConfigInterface>();

    public void Bar()
    {
        this.configMock.Setup(s => s.GetFoo()).Returns(1);
        // + other things out of scope for this question
    }

    // + other things out of scope for this question
}

public class Foo1Builder : TestBuilder<IFoo1Config>
{
    // + other things out of scope for this question
}

public class Foo2Builder : TestBuilder<IFoo2Config>
{
    // + other things out of scope for this question
}

然后 Foo1Engine 测试使用 Foo1Builder,Foo2Engine 测试使用 Foo2Builder(等等 x 很多)

我在上面的代码中遇到的问题是

public abstract class TestBuilder<GetFooableConfigInterface>
    where GetFooableConfigInterface : IGetFooableConfig, class

...导致错误

The 'class', 'struct', 'unmanaged', and 'notnull' constraints cannot be combined or duplicated, and must be specified first in the constraints list

如果我改为:

public abstract class TestBuilder<GetFooableConfigInterface>
    where GetFooableConfigInterface : IGetFooableConfig

我遇到了一个不同的问题

    Mock<GetFooableConfigInterface> configMock = new Mock<GetFooableConfigInterface>();

...导致错误

The type 'GetFooableConfigInterface' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Mock

这是因为起订量声明为public class Mock<T> : Mock, IMock<T> where T : class

如果我改为:

public abstract class TestBuilder<GetFooableConfigInterface>
    where GetFooableConfigInterface : class

这修复了上述两个错误,但引入了一个不同的问题

this.configMock.Setup(s => s.GetFoo()).Returns(1);

...导致错误

'GetFooableConfigInterface' does not contain a definition for 'Foo' and no accessible extension method 'Foo' accepting a first argument of type 'GetFooableConfigInterface' could be found (are you missing a using directive or an assembly reference?)

我如何说服编译器 GetFooableConfigInterface 既是 class 又是 IGetFooableConfig 的实现者?

谢谢

错误消息说:

The 'class' ... constraint ... must be specified first in the constraints list

因此您应该按以下顺序指定它:

public abstract class TestBuilder<GetFooableConfigInterface>
    where GetFooableConfigInterface : class, IGetFooableConfig
{

为什么要执行此命令,请参阅Why is some ordering enforced in generic parameter constraints?