question

TZacks-2728 avatar image
0 Votes"
TZacks-2728 asked TZacks-2728 commented

C# Null safety

when i code in c# with upper version i got warning like difference of a possible null reference i was reading a write up from this url https://docs.microsoft.com/en-us/learn/modules/csharp-null-safety/3-express-intent

i have some questions

 1) see this code and tell me difference
 a) FooBar? fooBar = null;
    
 // Same as FooBar fooBar = default!;
 b) FooBar fooBar = null!;


they said - This example adds the null-forgiving (!) operator to null, which instructs the compiler that you're explicitly initializing this variable as null. The compiler will not issue warnings about this reference being null.

if it means FooBar fooBar = null!; i am explicitly assign null to fooBar then i can assign something like this FooBar fooBar = null; then what would be difference?

2) can i instantiate like this way ?

 FooBar fooBar = new(Id: 1, Name: "Foo");

suppose FooBar is class which has 3 properties and can instantiate FooBar like this way ?

3) what is meaning of this FooBar fooBar = fooList.Find(f => f.Name == "Bar")!; ?

Thanks



dotnet-csharp
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered TZacks-2728 commented

I tend to steer away from the null-forgiving operator to appease the compiler, instead perform necessary asserts. No matter, the best way to learn is to first read the docs rather than jumping into code.

Here is something I slapped together without the null-forgiving operator

 public class Person
 {
     public int Id { get; set; }
     public string Name { get; set; }
 }
    
 public class Data
 {
     public static List<Person> Persons => new()
     {
         new() {Id = 1, Name = "Anne" },
         new() {Id = 2, Name = null }, // not needed
         new() {Id = 3, Name = "Mike" },
     };
 }

Then

 List<Person> people = Data.Persons;
    
 people.ForEach(person => Console.WriteLine(person.Name ?? "null"));
    
 var findName = "Mike";
 Person? mike = people.Find(person => person.Name == findName);
 if (mike is null)
 {
     Console.WriteLine($"Failed to find {findName}");
 }
 else
 {
     Console.WriteLine(mike.Id);
 }

Example with null forgiving, I know the list is good.

 public static List<Country> Countries()
 {
     var list = JsonSerializer.Deserialize<List<Country>>(File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Countries.json")));
    
     list!.Insert(0, new Country() { CountryIdentifier = -1, CountryName = "Select" });
    
     return list;
 }





· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you for help & clarification.

0 Votes 0 ·
Bruce-SqlWork avatar image
2 Votes"
Bruce-SqlWork answered TZacks-2728 commented

Null safety is a compile time feature. The compiler will try to detect when a null reference is possible. In your sample code


 // a nullable variable is set to null - no warning
 FooBar? fooBar = null;
    
 // a non nullable variable is set to null - will generate warning
 FooBar fooBar = null;
    
 // a non nullable variable is set to null - will not generate warning
 // you do this when you know the fooBar will be set to a valid value
 // before use, but don’t want to initial to a value that will not be used
 FooBar fooBar = null!;

Because null safety is not built into C# like it it is in rust or swift, the compiler can not trust that external code behaves properly.

If null safety enforced non nullable variables, you would not be able to use any library not built with enforcement.

Your final example is a good case

3) what is meaning of this?

FooBar fooBar = fooList.Find(f => f.Name == "Bar")!;

The Find() can return a null, so the compiler has to assume fooBar can also be set to null. The ! Is telling the compiler, you know that will not happen, and to assume in following statements fooBar is not null.

A better choice (if available) would to use First(), that would throw an error if not found. But you may know that even if fooBar is set to null from Find(), your code will not fall into a code path that would reference it.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thank you for help & clarification.

0 Votes 0 ·