asp.net-corenullblazorcompiler-warningsdevexpress-blazor

.NET 8 & Blazor components nullable warning with @ref


From what I understand the recommended method to hide null warnings on services is the following:

[Inject] private IExampleService ExampleService { get; set; } = default!;

https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/dependency-injection?view=aspnetcore-6.0#request-a-service-in-a-component

I'm wondering if the same applies to components that are given a reference in code behind with the @ref notation or if this should be handled differently?

For example using DevExpress components:

<DxButton Text="Button" @ref=ExampleButton />

@code {
    private DxButton ExampleButton { get; set; }  = default!;
}

If I understand this correctly the renderer populates the ExampleButton property after rendering so null exceptions are possible if the property is used in an OnInitialized() method therefor I am unsure if !default is the correct approach.

I was hoping DevExpress themselves would have some documentation about this, however I was unable to find anything.


Solution

  • The reason Injected services are define like this:

    [Inject] private IExampleService ExampleService { get; set; } = default!;
    

    is to suppress the null warnings in your development environment and compiler.

    The service is injected into the component by the Renderer when it creates a new component instance. If it can't find a service it throws an exception. By the time you get to use the service, in say OnInitializedAsync, it's guaranteed not to be null.

    You are correct that ExampleButton is null until after the first render, and trying to use it in OnInitializedAsync will cause an exception.

    Therefore it's unsafe, and negates the benefit of null checking.

    This is the correct declaration:

    private DxButton? ExampleButton { get; set; }
    

    Use the Null Conditional Operator if calling methods:

    ExampleButton?.DoSomething();
    

    Test for null if testing properties: you should rarely need do so, these are set/updated through parameters.

    You can in certain circumstances do something like this:

     ArgumentNullException.ThrowIfNull(object);
    

    To summarise:

    Only use =default! where you can guarantee that the value will not be null before you use it. Treat with extreme caution. Expect to justify it's use in a code review session!