How to initialize non-nullable strings in a class?
Asked Answered
N

1

5

I have this project:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.1" />
  </ItemGroup>
</Project>

This is the main class:

namespace CSharp8
{
    using System;
    using Microsoft.Extensions.Configuration;

    internal class Program
    {
        private static void Main()
        {
            var configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", false, true)
                .Build();
            var appSettings = configuration.Get<AppSettings>();
        }

        public class AppSettings
        {
            public string SourceServer { get; set; }
            public string TargetServer { get; set; }
        }
    }
}

This is appsettings.json:

{
  "SourceServer": "prodtools",
  "TargetServer": "qatools"
}

On the properties of AppSettings I get this warning:

Warning CS8618 Non-nullable property 'SourceServer' is uninitialized. Consider declaring the property as nullable.

I can fix it in different ways.

1.

public class AppSettings
{
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
    public string SourceServer { get; set; }
    public string TargetServer { get; set; }
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
}

I don't like this because I believe that rules must be consistent across the entire project.

2.

public class AppSettings
{
    public string SourceServer { get; set; } = "";
    public string TargetServer { get; set; } = "";
}

I don't like this because empty strings are the wrong values. The properties seem initialized but the values are meaningless and they will break my program if I fail to initialize them correctly.

3.

public class AppSettings
{
    public string SourceServer { get; set; } = null!;
    public string TargetServer { get; set; } = null!;
}

This makes sense, the instance is created with empty values and these values become initialized immediately. But I can't be sure that this code won't break in the future, because the properties are non-nullable.

4.

public class AppSettings
{
    public string? SourceServer { get; set; }
    public string? TargetServer { get; set; }
}

This makes sense too. For a microsecond, the properties will remain empty. But in my program they must have a value. So I don't like it either.

Which way do you think is the most feng shui? Any other suggestions? Thank you!

UPDATE Here's what I prefer now.

#nullable disable warnings
public class AppSettings
{
    public string SourceServer { get; set; }
    public string TargetServer { get; set; }
}

I still get null values in non-nullable properties, this is unavoidable, but at least it saves me from a lot of meaningless code, like = null!;

Navaho answered 2/12, 2019 at 9:5 Comment(3)
I am not convinced by your reasoning for 3, i.e. I would choose option 3. The settings must be set immediately as the program launches, right? If they are somehow not set when the program is running, then something very wrong has probably happened, and so you'd want it to crash, indicating that something very wrong has happened.Antonietta
This new nullable reference type thing is all about beeing explicit. You should not rely on unwritten implicit default values.So version 3 would make the most sense for this. And it's the default of any version prior C#8. Version 4 is quiet equivalent, just saying "it's allowed to be null" in another way - little less explicit. If you say the null is the exception, not the rule for you, go with 3.Wivestad
Option 3 looks good to me, but can we be sure that it will work forever? string s=null! sounds like int i=null!. Too bad I can't find a best practice at MSDN. Or am I missing something?Navaho
K
1

In this situation I tend to use the following, but I guess that its a matter of preference:

public class AppSettings
{
  public string SourceServer{ get; private set;} = string.Empty;
  public string TargetServer{ get; private set;} = string.Empty;
}

then before I use either of the values I check their values. Something like

var settings = new AppSettings();
if(string.IsNullOrWhitespace(settings.SourceServer)) 
{
 // Some error handling code
 return;
}

//process SourceServer value

I guess that you'll already be verifying the value before you store or use it anyway, so its not a problem.

Karlenekarlens answered 2/12, 2019 at 9:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.