diff --git a/Source/Proxy/CastleProxyFactory.cs b/Source/Proxy/CastleProxyFactory.cs index 9f5fa54a9..c08ce9113 100644 --- a/Source/Proxy/CastleProxyFactory.cs +++ b/Source/Proxy/CastleProxyFactory.cs @@ -120,10 +120,15 @@ public Type GetDelegateProxyInterface(Type delegateType, out MethodInfo delegate var delegateParameterTypes = invokeMethodOnDelegate.GetParameters().Select(p => p.ParameterType).ToArray(); // Create a method on the interface with the same signature as the delegate. - newTypeBuilder.DefineMethod("Invoke", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract, - CallingConventions.HasThis, - invokeMethodOnDelegate.ReturnType, delegateParameterTypes); + var newMethBuilder = newTypeBuilder.DefineMethod("Invoke", + MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract, + CallingConventions.HasThis, + invokeMethodOnDelegate.ReturnType, delegateParameterTypes); + + foreach (var param in invokeMethodOnDelegate.GetParameters()) + { + newMethBuilder.DefineParameter(param.Position + 1, param.Attributes, param.Name); + } delegateInterfaceType = newTypeBuilder.CreateType(); delegateInterfaceCache[delegateType] = delegateInterfaceType; diff --git a/UnitTests/MockedDelegatesFixture.cs b/UnitTests/MockedDelegatesFixture.cs index 23e997310..889b89a88 100644 --- a/UnitTests/MockedDelegatesFixture.cs +++ b/UnitTests/MockedDelegatesFixture.cs @@ -86,6 +86,78 @@ public void DelegateInterfacesAreReused() Assert.Same(mock1.DelegateInterfaceMethod, mock2.DelegateInterfaceMethod); } + [Fact] + public void CanHandleOutParameterOfActionAsSameAsVoidMethod() + { + var out1 = 42; + var methMock = new Mock>(); + methMock.Setup(t => t.Invoke(out out1)); + var dlgtMock = new Mock>(); + dlgtMock.Setup(f => f(out out1)); + + var methOut1 = default(int); + methMock.Object.Invoke(out methOut1); + var dlgtOut1 = default(int); + dlgtMock.Object(out dlgtOut1); + + Assert.Equal(methOut1, dlgtOut1); + } + + [Fact] + public void CanHandleRefParameterOfActionAsSameAsVoidMethod() + { + var ref1 = 42; + var methMock = new Mock>(MockBehavior.Strict); + methMock.Setup(t => t.Invoke(ref ref1)); + var dlgtMock = new Mock>(MockBehavior.Strict); + dlgtMock.Setup(f => f(ref ref1)); + + var methRef1 = 42; + methMock.Object.Invoke(ref methRef1); + var dlgtRef1 = 42; + dlgtMock.Object(ref dlgtRef1); + + methMock.VerifyAll(); + dlgtMock.VerifyAll(); + } + + [Fact] + public void CanHandleOutParameterOfFuncAsSameAsReturnableMethod() + { + var out1 = 42; + var methMock = new Mock>(); + methMock.Setup(t => t.Invoke(out out1)).Returns(114514); + var dlgtMock = new Mock>(); + dlgtMock.Setup(f => f(out out1)).Returns(114514); + + var methOut1 = default(int); + var methResult = methMock.Object.Invoke(out methOut1); + var dlgtOut1 = default(int); + var dlgtResult = dlgtMock.Object(out dlgtOut1); + + Assert.Equal(methOut1, dlgtOut1); + Assert.Equal(methResult, dlgtResult); + } + + [Fact] + public void CanHandleRefParameterOfFuncAsSameAsReturnableMethod() + { + var ref1 = 42; + var methMock = new Mock>(MockBehavior.Strict); + methMock.Setup(t => t.Invoke(ref ref1)).Returns(114514); + var dlgtMock = new Mock>(MockBehavior.Strict); + dlgtMock.Setup(f => f(ref ref1)).Returns(114514); + + var methRef1 = 42; + var methResult = methMock.Object.Invoke(ref methRef1); + var dlgtRef1 = 42; + var dlgtResult = dlgtMock.Object(ref dlgtRef1); + + methMock.VerifyAll(); + dlgtMock.VerifyAll(); + Assert.Equal(methResult, dlgtResult); + } + private static void Use(Action action, int valueToPass) { action(valueToPass); @@ -115,5 +187,14 @@ public int Value } } } + + public interface TypeOutAction { void Invoke(out TOut1 out1); } + public delegate void DelegateOutAction(out TOut1 out1); + public interface TypeRefAction { void Invoke(ref TRef1 ref1); } + public delegate void DelegateRefAction(ref TRef1 ref1); + public interface TypeOutFunc { TResult Invoke(out TOut1 out1); } + public delegate TResult DelegateOutFunc(out TOut1 out1); + public interface TypeRefFunc { TResult Invoke(ref TRef1 ref1); } + public delegate TResult DelegateRefFunc(ref TRef1 ref1); } }