Describe the bug
When two returns are configured on the same generic method, and the two closed type arguments are related by inheritance, configuring the second call throws an InvalidCastException. NSubstitute appears to hand back the value stored for the first configuration while recording the second call, then fails to cast it to the second call's return type.
This works in 5.3.0 and breaks in 6.0.0.
This was found with MediatR's IMediator.Send<TResponse>(IRequest<TResponse>), where different request types resolve TResponse to IResult vs IResult<T>.
To Reproduce
Create and run this console application. When NSubstitute is on version 5.3.0 the application writes "No Errors" to the console. When NSubstitute is on version 6.0.0 the application throws a System.InvalidCastException.
program.cs
using NSubstitute;
var sub = Substitute.For<ISender>();
sub.Send(Arg.Any<NonGenericRequest>()).Returns(Substitute.For<IResult>());
sub.Send(Arg.Any<GenericRequest>()).Returns(Substitute.For<IResult<int>>());
Console.WriteLine("No errors");
public interface IResult { }
public interface IResult<T> : IResult { }
public interface IRequest<TResponse> { }
public class NonGenericRequest : IRequest<IResult> { }
public class GenericRequest : IRequest<IResult<int>> { }
public interface ISender
{
Task<TResponse> Send<TResponse>(IRequest<TResponse> request);
}
csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<!-- <PackageReference Include="NSubstitute" Version="6.0.0" />-->
<PackageReference Include="NSubstitute" Version="5.3.0" />
</ItemGroup>
</Project>
Expected behaviour
I would expect this to behave like 5.3.0 and not throw an exception.
Environment:
- NSubstitute version: 6.0.0
- Platform: net10 project on Windows
Workaround
Use Arg.Is so it doesn't match the null recording placeholder:
sub.Send(Arg.Is<NonGenericRequest>(r => r != null)).Returns(Substitute.For<IResult>());
sub.Send(Arg.Is<GenericRequest>(r => r != null)).Returns(Substitute.For<IResult<int>>());
Describe the bug
When two returns are configured on the same generic method, and the two closed type arguments are related by inheritance, configuring the second call throws an
InvalidCastException. NSubstitute appears to hand back the value stored for the first configuration while recording the second call, then fails to cast it to the second call's return type.This works in 5.3.0 and breaks in 6.0.0.
This was found with MediatR's
IMediator.Send<TResponse>(IRequest<TResponse>), where different request types resolveTResponsetoIResultvsIResult<T>.To Reproduce
Create and run this console application. When NSubstitute is on version 5.3.0 the application writes "No Errors" to the console. When NSubstitute is on version 6.0.0 the application throws a System.InvalidCastException.
program.cs
csproj
Expected behaviour
I would expect this to behave like 5.3.0 and not throw an exception.
Environment:
Workaround
Use Arg.Is so it doesn't match the
nullrecording placeholder: