I have been reading the introductory guide for primary constructors in c#12 and I'm getting some unexpected results (https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/primary-constructors).
I have some code like:
public class ServiceA(IServiceB service){ public async Task<bool> Method() { return await service.GetValue(); }}
Now, if I create a unit test like this:
[Fact]public void Test1() { var mockB = Substitute.For<IServiceB>(); _sut = new SeviceA(mockB); _sut.Method(); Assert.NotNull(mockB);}
In the call to _sut.Method();
, inside, the service
that is provided in the test via a mock, it's actually null
in ServiceA.Method. The mock is correctly created in the unit test, but it doesn't make it to the method.
A way I found to solve this is by creating a property or field to capture the Primary constructor parameter and then use that instead of the parameter. Something like this:
public class ServiceA(IServiceB service){ private IServiceB ServiceProperty { get; } = service; //capture the parameter public async Task<bool> Method() { return await ServiceProperty.GetValue(); //use property instead of parameter }}
As I said, the above now works, however from what I understand from the docs, that parameter capturing should not be necessary: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/primary-constructors#dependency-injection
Another common use for primary constructors is to specify parameters for dependency injection. The following code creates a simple controller that requires a service interface for its use:C#
public interface IService { Distance GetDistance(); } public class ExampleController(IService service) : ControllerBase { [HttpGet] public ActionResult<Distance> Get() { return service.GetDistance(); }}
The primary constructor clearly indicates the parameters needed in the class. You use the primary constructor parameters as you would any other variable in the class.
-> Am I misunderstanding Primary constructors?