Skip to content

Unable to mock interfaces that consume value types by reference #378

@TAGC

Description

@TAGC

C# 7.2 introduced the possibility of using reference semantics for value types - this is done by applying the in modifier for value-type parameters in method signatures.

NSubstitute is apparently not able to generate mocks for interfaces that use these new modifiers. Given the unit tests below:

using NSubstitute;
using Xunit;

namespace SomeProject.Tests
{
    public readonly struct Struct
    {
    }

    public interface IStructByRefConsumer
    {
        void Consume(in Struct message);
    }

    public interface IStructByValueConsumer
    {
        void Consume(Struct message);
    }

    public class TempSpec
    {
        // Fails.
        [Fact]
        internal void IStructByRefConsumer_Test()
        {
            _ = Substitute.For<IStructByRefConsumer>();
        }

        // Passes.
        [Fact]
        internal void IStructByValueConsumer_Test()
        {
            _ = Substitute.For<IStructByValueConsumer>();
        }
    }
}

What I find is that IStructByValueConsumer_Test passes as expected, while IStructByRefConsumer_Test fails with this exception:

Test Name:	SomeProject.Tests.TempSpec.IStructByRefConsumer_Test
Test FullName:	SomeProject.Tests.TempSpec.IStructByRefConsumer_Test
Test Source:	C:\path\to\tests\TempSpec.cs : line 30
Test Outcome:	Failed
Test Duration:	0:00:22.187

Result StackTrace:	
at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type)
   at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
   at System.Reflection.Emit.TypeBuilder.CreateTypeInfo()
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.CreateType(TypeBuilder type)
   at Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
   at Castle.DynamicProxy.Generators.InterfaceProxyWithoutTargetGenerator.GenerateType(String typeName, Type proxyTargetType, Type[] interfaces, INamingScope namingScope)
   at Castle.DynamicProxy.Generators.InterfaceProxyWithTargetGenerator.<>c__DisplayClass6_0.<GenerateCode>b__0(String n, INamingScope s)
   at Castle.DynamicProxy.Generators.BaseProxyGenerator.ObtainProxyType(CacheKey cacheKey, Func`3 factory)
   at Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type interfaceToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleDynamicProxyFactory.GenerateProxy(ICallRouter callRouter, Type typeToProxy, Type[] additionalInterfaces, Object[] constructorArguments)
   at NSubstitute.Core.SubstituteFactory.Create(Type[] typesToProxy, Object[] constructorArguments, SubstituteConfig config)
   at NSubstitute.Substitute.For[T](Object[] constructorArguments)
   at SomeProject.Tests.TempSpec.IStructByRefConsumer_Test() in C:\path\to\tests\TempSpec.cs:line 32
Result Message:	System.TypeLoadException : Signature of the body and declaration in a method implementation do not match.  Type: 'Castle.Proxies.IStructByRefConsumerProxy'.  Assembly: 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions