尝试将 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?
我正在尝试为许多“引擎”编写单元测试。每种引擎类型都有不同的“配置”,但在它们的实例化方式、其他参数以及模拟如何全部需要挂在一起方面存在明显的重叠。为了解决这个问题,我有一个通用的测试助手 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?