Setup.Callback() 未被调用

Setup.Callback() is not being called

我有一个 Setup.Callback() 操作未在 VB.NET 中调用。它在 C# 中按预期工作。代码转换正确。

VB.NET

Private Function CreateFriendEditViewModel() As IFriendEditViewModel
  Dim oWrapper As FriendWrapper
  Dim oFriend As [Friend]
  Dim oMock As Mock(Of IFriendEditViewModel)

  oMock = New Mock(Of IFriendEditViewModel)
  oMock.
    Setup(Sub(Vm) Vm.Load(It.IsAny(Of Integer))).
    Callback(Of Integer?)(Sub(FriendId)
                            oFriend = New [Friend] With {.Id = FriendId.Value}
                            oWrapper = New FriendWrapper(oFriend)

                            oMock.
                              Setup(Function(Vm) Vm.Friend).
                              Returns(oWrapper)
                          End Sub)

  Me.FriendEditViewModelMocks.Add(oMock)

  Return oMock.Object
End Function

C#

private IFriendEditViewModel CreateFriendEditViewModel()
{
  var friendEditViewModelMock = new Mock<IFriendEditViewModel>();
  friendEditViewModelMock
    .Setup(vm => vm.Load(It.IsAny<int>()))
    .Callback<int?>(friendId =>
    {
      friendEditViewModelMock
        .Setup(vm => vm.Friend)
        .Returns(new FriendWrapper(new Friend { Id = friendId.Value }));
    });
  _friendEditViewModelMocks.Add(friendEditViewModelMock);
  return friendEditViewModelMock.Object;
}

请注意,当我将 Nullable(Of Integer) 类型更改为 Integer 时,它在 VB.NET 中有效。

在抓吸管的时候,我尝试了这个细微的变化:

oMock.
  Setup(Function(Vm) Vm.Friend).
  Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))

...但没有帮助。

这三个问答都没有说明情况:

我是 Moq 的初学者,所以这让我感到困惑。

谁能看出这里出了什么问题?为什么我的回调没有被调用,为什么这个失败只发生在 VB.NET?

--更新--

我查看了这四种情况中每一种的 IL(通过 JustDecompile):

  1. VB.NET using type Integer (succeeds)
Callback(Of Integer)(Sub(FriendId)
                       oMock.
                          Setup(Function(Vm) Vm.Friend).
                          Returns(New FriendWrapper(New [Friend] With {.Id = FriendId}))
                     End Sub)

.method private instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
    .locals init (
        [0] class FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0' $VB$Closure_0,
        [1] class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel,
        [2] class [System.Core]System.Linq.Expressions.ParameterExpression V_2
    )

    IL_0000: nop
    IL_0001: newobj instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::.ctor()
    IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_0012: ldloc.0
    IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel
    IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0022: ldstr "Vm"
    IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type,  string)
    IL_002c: stloc.2
    IL_002d: ldloc.2
    IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel::Load(valuetype [mscorlib]System.Nullable`1<int32>)
    IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
    IL_003d: ldc.i4.1
    IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
    IL_0043: dup
    IL_0044: ldc.i4.0
    IL_0045: ldnull
    IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
    IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
    IL_0055: ldc.i4.0
    IL_0056: newarr [System.Core]System.Linq.Expressions.Expression
    IL_005b: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_0060: ldtoken valuetype [mscorlib]System.Nullable`1<int32>
    IL_0065: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_006a: call class [System.Core]System.Linq.Expressions.UnaryExpression [System.Core]System.Linq.Expressions.Expression::ConvertChecked(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Type)
    IL_006f: stelem.ref
    IL_0070: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_0075: ldc.i4.1
    IL_0076: newarr [System.Core]System.Linq.Expressions.ParameterExpression
    IL_007b: dup
    IL_007c: ldc.i4.0
    IL_007d: ldloc.2
    IL_007e: stelem.ref
    IL_007f: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression,  class [System.Core]System.Linq.Expressions.ParameterExpression[])
    IL_0084: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
    IL_0089: ldloc.0
    IL_008a: ldftn instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::_Lambda$__0(int32)
    IL_0090: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object,  native int)
    IL_0095: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<int32>(class [mscorlib]System.Action`1<int32>)
    IL_009a: pop
    IL_009b: ldarg.0
    IL_009c: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> FriendStorage.UI.Tests.ViewModels.MainViewModelTests::FriendEditViewModelMocks
    IL_00a1: ldloc.0
    IL_00a2: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_00a7: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>::Add(!0)
    IL_00ac: nop
    IL_00ad: ldloc.0
    IL_00ae: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_00b3: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::get_Object()
    IL_00b8: stloc.1
    IL_00b9: br.s IL_00bb

    IL_00bb: ldloc.1
    IL_00bc: ret
}
  1. VB.NET using type Integer? (fails)
Callback(Of Integer?)(Sub(FriendId)
                        oMock.
                          Setup(Function(Vm) Vm.Friend).
                          Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))
                      End Sub)

.method private instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
    .locals init (
        [0] class FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0' $VB$Closure_0,
        [1] class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel CreateFriendEditViewModel,
        [2] class [System.Core]System.Linq.Expressions.ParameterExpression V_2
    )

    IL_0000: nop
    IL_0001: newobj instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::.ctor()
    IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_0012: ldloc.0
    IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel
    IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0022: ldstr "Vm"
    IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type,  string)
    IL_002c: stloc.2
    IL_002d: ldloc.2
    IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel::Load(valuetype [mscorlib]System.Nullable`1<int32>)
    IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
    IL_003d: ldc.i4.1
    IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
    IL_0043: dup
    IL_0044: ldc.i4.0
    IL_0045: ldnull
    IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
    IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
    IL_0055: ldc.i4.0
    IL_0056: newarr [System.Core]System.Linq.Expressions.Expression
    IL_005b: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_0060: ldtoken valuetype [mscorlib]System.Nullable`1<int32>
    IL_0065: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_006a: call class [System.Core]System.Linq.Expressions.UnaryExpression [System.Core]System.Linq.Expressions.Expression::ConvertChecked(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Type)
    IL_006f: stelem.ref
    IL_0070: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_0075: ldc.i4.1
    IL_0076: newarr [System.Core]System.Linq.Expressions.ParameterExpression
    IL_007b: dup
    IL_007c: ldc.i4.0
    IL_007d: ldloc.2
    IL_007e: stelem.ref
    IL_007f: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression,  class [System.Core]System.Linq.Expressions.ParameterExpression[])
    IL_0084: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
    IL_0089: ldloc.0
    IL_008a: ldftn instance void FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::_Lambda$__0(valuetype [mscorlib]System.Nullable`1<int32>)
    IL_0090: newobj instance void class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>::.ctor(object,  native int)
    IL_0095: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<valuetype [mscorlib]System.Nullable`1<int32>>(class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>)
    IL_009a: pop
    IL_009b: ldarg.0
    IL_009c: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>> FriendStorage.UI.Tests.ViewModels.MainViewModelTests::FriendEditViewModelMocks
    IL_00a1: ldloc.0
    IL_00a2: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_00a7: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>>::Add(!0)
    IL_00ac: nop
    IL_00ad: ldloc.0
    IL_00ae: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel> FriendStorage.UI.Tests.ViewModels.MainViewModelTests/'_Closure$__5-0'::$VB$Local_oMock
    IL_00b3: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModels.IFriendEditViewModel>::get_Object()
    IL_00b8: stloc.1
    IL_00b9: br.s IL_00bb

    IL_00bb: ldloc.1
    IL_00bc: ret
}
  1. C# using type int (succeeds)
.Callback<int>(friendId =>
{
  friendEditViewModelMock
    .Setup(vm => vm.Friend)
    .Returns(new FriendWrapper(new Friend { Id = friendId }));
});

.method private hidebysig instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
    .locals init (
        [0] class FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0' 'CS$<>8__locals0',
        [1] class [System.Core]System.Linq.Expressions.ParameterExpression V_1,
        [2] class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel V_2
    )

    IL_0000: newobj instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::.ctor()
    IL_0005: stloc.0
    IL_0006: nop
    IL_0007: ldloc.0
    IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::.ctor()
    IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_0012: ldloc.0
    IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel
    IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0022: ldstr "vm"
    IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type,  string)
    IL_002c: stloc.1
    IL_002d: ldloc.1
    IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel::Load(int32)
    IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
    IL_003d: ldc.i4.1
    IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
    IL_0043: dup
    IL_0044: ldc.i4.0
    IL_0045: ldnull
    IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
    IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
    IL_0055: call class [System.Core]System.Linq.Expressions.Expression[] [mscorlib]System.Array::Empty<class [System.Core]System.Linq.Expressions.Expression>()
    IL_005a: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_005f: stelem.ref
    IL_0060: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_0065: ldc.i4.1
    IL_0066: newarr [System.Core]System.Linq.Expressions.ParameterExpression
    IL_006b: dup
    IL_006c: ldc.i4.0
    IL_006d: ldloc.1
    IL_006e: stelem.ref
    IL_006f: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression,  class [System.Core]System.Linq.Expressions.ParameterExpression[])
    IL_0074: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
    IL_0079: ldloc.0
    IL_007a: ldftn instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::'<CreateFriendEditViewModel>b__1'(int32)
    IL_0080: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object,  native int)
    IL_0085: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<int32>(class [mscorlib]System.Action`1<int32>)
    IL_008a: pop
    IL_008b: ldarg.0
    IL_008c: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> FriendStorage.UITests.ViewModel.MainViewModelTests::_friendEditViewModelMocks
    IL_0091: ldloc.0
    IL_0092: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_0097: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>::Add(!0)
    IL_009c: nop
    IL_009d: ldloc.0
    IL_009e: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_00a3: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::get_Object()
    IL_00a8: stloc.2
    IL_00a9: br.s IL_00ab

    IL_00ab: ldloc.2
    IL_00ac: ret
}
  1. C# using type int? (succeeds)
.Callback<int?>(friendId =>
{
  friendEditViewModelMock
    .Setup(vm => vm.Friend)
    .Returns(new FriendWrapper(new Friend { Id = friendId.Value }));
});

.method private hidebysig instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel CreateFriendEditViewModel () cil managed
{
    .locals init (
        [0] class FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0' 'CS$<>8__locals0',
        [1] class [System.Core]System.Linq.Expressions.ParameterExpression V_1,
        [2] class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel V_2
    )

    IL_0000: newobj instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::.ctor()
    IL_0005: stloc.0
    IL_0006: nop
    IL_0007: ldloc.0
    IL_0008: newobj instance void class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::.ctor()
    IL_000d: stfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_0012: ldloc.0
    IL_0013: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_0018: ldtoken [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel
    IL_001d: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0022: ldstr "vm"
    IL_0027: call class [System.Core]System.Linq.Expressions.ParameterExpression [System.Core]System.Linq.Expressions.Expression::Parameter(class [mscorlib]System.Type,  string)
    IL_002c: stloc.1
    IL_002d: ldloc.1
    IL_002e: ldtoken method instance void [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel::Load(valuetype [mscorlib]System.Nullable`1<int32>)
    IL_0033: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0038: castclass [mscorlib]System.Reflection.MethodInfo
    IL_003d: ldc.i4.1
    IL_003e: newarr [System.Core]System.Linq.Expressions.Expression
    IL_0043: dup
    IL_0044: ldc.i4.0
    IL_0045: ldnull
    IL_0046: ldtoken method int32 [Moq]Moq.It::IsAny<int32>()
    IL_004b: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle)
    IL_0050: castclass [mscorlib]System.Reflection.MethodInfo
    IL_0055: call class [System.Core]System.Linq.Expressions.Expression[] [mscorlib]System.Array::Empty<class [System.Core]System.Linq.Expressions.Expression>()
    IL_005a: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_005f: ldtoken valuetype [mscorlib]System.Nullable`1<int32>
    IL_0064: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    IL_0069: call class [System.Core]System.Linq.Expressions.UnaryExpression [System.Core]System.Linq.Expressions.Expression::Convert(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Type)
    IL_006e: stelem.ref
    IL_006f: call class [System.Core]System.Linq.Expressions.MethodCallExpression [System.Core]System.Linq.Expressions.Expression::Call(class [System.Core]System.Linq.Expressions.Expression,  class [mscorlib]System.Reflection.MethodInfo,  class [System.Core]System.Linq.Expressions.Expression[])
    IL_0074: ldc.i4.1
    IL_0075: newarr [System.Core]System.Linq.Expressions.ParameterExpression
    IL_007a: dup
    IL_007b: ldc.i4.0
    IL_007c: ldloc.1
    IL_007d: stelem.ref
    IL_007e: call class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> [System.Core]System.Linq.Expressions.Expression::Lambda<class [mscorlib]System.Action`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>(class [System.Core]System.Linq.Expressions.Expression,  class [System.Core]System.Linq.Expressions.ParameterExpression[])
    IL_0083: callvirt instance class [Moq]Moq.Language.Flow.ISetup`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::Setup(class [System.Core]System.Linq.Expressions.Expression`1<class [mscorlib]System.Action`1<!0>>)
    IL_0088: ldloc.0
    IL_0089: ldftn instance void FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::'<CreateFriendEditViewModel>b__1'(valuetype [mscorlib]System.Nullable`1<int32>)
    IL_008f: newobj instance void class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>::.ctor(object,  native int)
    IL_0094: callvirt instance class [Moq]Moq.Language.Flow.ICallbackResult [Moq]Moq.Language.ICallback::Callback<valuetype [mscorlib]System.Nullable`1<int32>>(class [mscorlib]System.Action`1<valuetype [mscorlib]System.Nullable`1<int32>>)
    IL_0099: pop
    IL_009a: ldarg.0
    IL_009b: ldfld class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>> FriendStorage.UITests.ViewModel.MainViewModelTests::_friendEditViewModelMocks
    IL_00a0: ldloc.0
    IL_00a1: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_00a6: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>>::Add(!0)
    IL_00ab: nop
    IL_00ac: ldloc.0
    IL_00ad: ldfld class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel> FriendStorage.UITests.ViewModel.MainViewModelTests/'<>c__DisplayClass6_0'::friendEditViewModelMock
    IL_00b2: callvirt instance class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel class [Moq]Moq.Mock`1<class [FriendStorage.UI]FriendStorage.UI.ViewModel.IFriendEditViewModel>::get_Object()
    IL_00b7: stloc.2
    IL_00b8: br.s IL_00ba

    IL_00ba: ldloc.2
    IL_00bb: ret
}

我曾希望能有什么东西跳出来并且很容易被发现,但不幸的是,IL 对我来说仍然是个谜。也就是说,我注意到 VB 和 C# 版本之间存在显着差异。事实上,C# int/int? 版本之间甚至存在很大差异。 VB 中的 Integer/Integer? 之间没有那么多。

作为安全检查,我还实施了 Try/Catch

Callback(Of Integer?)(Sub(FriendId)
                        Try
                          oMock.
                            Setup(Function(Vm) Vm.Friend).
                            Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))

                        Catch ex As Exception
                          Debug.WriteLine(ex.Message)

                        End Try
                      End Sub)

仍然没有变化。在 VB 中使用 Nullable(Of Integer) 时,根本不会调用回调。我很想在那里的某个地方设置一个断点,但如果执行永远不会到达该代码块,它不会有任何好处。

这是我当前项目的阻碍,所以我召集了所有专家。

当我使用 Instant VB 转换该 C# 代码时,我得到以下信息:

Private Function CreateFriendEditViewModel() As IFriendEditViewModel
    Dim friendEditViewModelMock = New Mock(Of IFriendEditViewModel)

    friendEditViewModelMock.
        Setup(Function(vm) vm.Load(It.IsAny(Of Integer)())).
        Callback(Of Integer?)(Sub(friendId)
                                  friendEditViewModelMock.
                                      Setup(Function(vm) vm.Friend).
                                      Returns(New FriendWrapper(New [Friend] With {.Id = friendId.Value}))
                              End Sub)

    _friendEditViewModelMocks.Add(friendEditViewModelMock)

    Return friendEditViewModelMock.Object
End Function

请注意,传递给 Setup 的 Lambda 表达式都是 Function 而不是 Sub。我不是 100% 确定,但我怀疑这可能是你的问题。

好的,明白了。

这是 IFriendEditViewModel 签名:

Public Interface IFriendEditViewModel
  Sub Load(FriendId As Integer?)
  ReadOnly Property [Friend] As FriendWrapper
End Interface

...这里又是原来的 setup/callback:

Private Function CreateFriendEditViewModel() As IFriendEditViewModel
  Dim oMock = New Mock(Of IFriendEditViewModel)

  oMock.
    Setup(Sub(Vm) Vm.Load(It.IsAny(Of Integer))).
    Callback(Of Integer?)(Sub(FriendId)
                            oMock.
                              Setup(Function(Vm) Vm.Friend).
                              Returns(New FriendWrapper(New [Friend] With {.Id = FriendId.Value}))
                          End Sub)

  Me.FriendEditViewModelMocks.Add(oMock)

  Return oMock.Object
End Function

看到问题了吗? Vm.Load() 方法采用 Nullable(Of Integer)。我之前错过了这个小细节;我正在从 C# 转换,在这种情况下显然允许混合参数类型。出乎意料的是,它构建并运行得很好:

private IFriendEditViewModel CreateFriendEditViewModel()
{
  var friendEditViewModelMock = new Mock<IFriendEditViewModel>();
  friendEditViewModelMock
    .Setup(vm => vm.Load(It.IsAny<int>())) // <== Oops!
    .Callback<int?>(friendId =>
    {
      friendEditViewModelMock
        .Setup(vm => vm.Friend)
        .Returns(new FriendWrapper(new Friend { Id = friendId.Value }));
    });
  _friendEditViewModelMocks.Add(friendEditViewModelMock);
  return friendEditViewModelMock.Object;
}

所以,我只是将我的设置参数更改为:

Setup(Sub(Vm) Vm.Load(It.IsAny(Of Integer?)))

...它直接通过了。回调按预期调用。

事实上,我不完全确定我不会将此称为 C# 编译器中的错误。