C# 使用NSubstitute的LINQPad中的奇怪行为
我在LINQPad 4(C# 使用NSubstitute的LINQPad中的奇怪行为,c#,linqpad,nsubstitute,C#,Linqpad,Nsubstitute,我在LINQPad 4(v.4.57.02)中编写了以下示例,以演示试图使用NSubstitute(v1.9.2.0)模拟类型及其非虚拟属性的愚蠢行为: void Main() { var foo = Substitute.For<Foo>(); foo.Alarm.Returns(2); foo.Alarm.Dump(); } public class Foo { public Foo() { Console.Wri
v.4.57.02
)中编写了以下示例,以演示试图使用NSubstitute(v1.9.2.0
)模拟类型及其非虚拟属性的愚蠢行为:
void Main()
{
var foo = Substitute.For<Foo>();
foo.Alarm.Returns(2);
foo.Alarm.Dump();
}
public class Foo
{
public Foo()
{
Console.WriteLine("Foo ctor called.");
}
public virtual int Alarm
{
get; set;
}
}
现在,当我编辑代码以删除报警
属性上的虚拟
修饰符时,我希望看到一个NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException
异常,其中包括:
如果替换了类而不是接口,请检查对替换对象的调用是否在虚拟/抽象成员上。无法为非虚拟/非抽象成员配置返回值
但是,我第一次运行修改后的代码时得到:
Foo ctor called.
0
在随后的运行中,我得到了预期的异常
现在我怀疑LINQPad管理AppDomains的方式和NSubstitute的Castle代理的工作方式有点滑稽,但我不知道是什么。举起手来,我只是没时间深入研究,并且想知道是否有其他人有明确的解释,因为了解LINQPad执行环境中的gotchas会让人感到安慰。如果您开始打开一个新的LINQPad实例,并在没有
虚拟
成员的情况下运行代码,它将立即失败,并出现预期的错误
这是我对正在发生的事情的猜测。第一次使用virtual
成员NSubstitute的状态运行代码时如下所示:
var foo = Substitute.For<Foo>();
foo.Alarm // 1. last call is foo.Alarm
.Returns(2); // 2. make foo.Alarm return `2`. Clear last call.
foo.Alarm // 3. last call is foo.Alarm
.Dump(); // 4. extension method -- doesn't clear last call
var foo=Substitute.For();
foo.Alarm//1。最后一个电话是foo.Alarm
.返回(2);//2.使foo.Alarm返回'2'。清除最后一个呼叫。
foo.Alarm//3。最后一个电话是foo.Alarm
.Dump();//4.扩展方法--不清除上次调用
NSSubstitute静态存储对替换的最后一次调用,因此它将一直挂起,直到appdomain消失。当您修改代码以删除
虚拟
并再次运行它时,步骤2中的.Returns(2)
会找到在上一次运行的步骤3中进行的最后一次调用,相应地将其存根,然后清除最后一次调用。由于非虚拟成员的原因,不会记录进一步的调用,因此后续运行会失败,并出现预期错误。这当然很有意义。不错。另外,需要注意的是,上一次运行的调用是在stubbed对象的另一个实例上进行的,这意味着.Returns(2)
调用是在一个对象上进行的,该对象不再可以从LINQPad代码访问,而是可以从NSubstitute中“last call”概念的静态存储中访问。
var foo = Substitute.For<Foo>();
foo.Alarm // 1. last call is foo.Alarm
.Returns(2); // 2. make foo.Alarm return `2`. Clear last call.
foo.Alarm // 3. last call is foo.Alarm
.Dump(); // 4. extension method -- doesn't clear last call