In new version of C# is default option nullable. I mean this
It's really good feature for me. But I don't understand one thing. Is property nullable by me or by program?
I know that this property should never be null because I fill it in the form and never set it as null. But in general it can be null. How should I mark it?
Example:
UserModel:
public string? Name { get; set; }
public string Name { get; set; } = null!
I'm really confused.
I know that this property should never be null because I fill it in
the form and never set it as null. But in general it can be null. How
should I mark it?
If it is set to non-null in the constructor, then you can declare it a string rather than string? because it really is guaranteed to never be null.
If, however, it is null after the constructor has run (and before any other methods are called) then it CAN be null and you should declare it as string?.
The dichotomy you face is that (from what you say) it should never be null when the class is used correctly - i.e. if the calling code does indeed call the method that initialises the property to non-null before accessing it, it will be guaranteed to be not null - which means you would like to declare it as a non-null string so that callers don't need to use the null-forgiving ! operator to suppress nullable warnings.
What to do in this case? Well I think you have three possibilities:
Declare the property as nullable: string? and let the callers suppress the nullable warning or check the value for null.
Initialise the property to a non-null default such as string.Empty and declare the property as non nullable string.
Assume that accessing the property when it is null is a programming error, and throw an appropriate exception.
For the last case, you could do something like this:
private string? _name;
public string Name
{
get
{
if (_name == null)
throw new InvalidOperationException("Do not access Name without setting it to non-null or calling Init()");
return _name;
}
set
{
if (value == null)
throw new ArgumentNullException("value", "You cannot set Name to null.");
_name = value;
}
}
This assumes that there's a method called Init() that can be called to initialise Name, but of course your code may vary.
Regardless of which of those approaches you take, you should really check for null in the property setter, as shown above.
Note that a more succinct way of writing the setter null check is:
set
{
_name = value ?? throw new ArgumentNullException("value", "You cannot set Name to null.");
}
Where a value can be null, and the <Nullable>enable</Nullable> value is set in your *.csproj file, you must declare those values as nullable.
In your given example, the nullable type (instead of assigning null as a default) is the way to go:
public string? Name {get; set;}
You'll also notice VS complaining at you with warnings every time you introduce a property etc which can be nullable, but isn't marked as such.
Why do I not get a non-nullable warning (or some other warning) for FieldTwo not being set in the constructor? I'm using .Net 5.0 and Nullable option is set to true in the project file.
public class MyClass
{
public string FieldOne;
public long FieldTwo;
public MyClass (string p1, long p2)
{
FieldOne = p1;
// FieldTwo is not set. Where is the non-nullable warning!?
}
}
long is a value type and cannot be null. So there is no reason for warn about null. What I suspect you want is a field not initialized warning.
If a private field is never assigned, it causes a CS0649 warning. However, if the field public, or is modified anywhere in the class, this warning is not raised. For example, the following would be perfectly acceptable code, and should not give a warning:
public class MyClass{
private long myLong;
public void Increment() => myLong++;
}
If the field should only be set from the constructor you should declare it as readonly. However, public readonly fields does not trigger a warning, even if they probably should. See Why do I NOT get warnings about uninitialized readonly fields?.
long is a value type and can't be null. Value types are always initialized when declared with a default value, in this case 0. You'd have to change the field type to long? if you wanted to store a null
Those fields aren't properties anyway. This isn't just semantics. Fields are implementation details, even public fields. They aren't considered part of a class's API surface. Properties are part of the API, they get serialized by default by all serializers (fields don't) and guarantee In fact having public fields is a code smell.
To ensure all properties are initialized you can use a record type instead of a class :
public record(string PropertyOne, long PropertyTwo);
This generates a class with init-only properties for PropertyOne and PropertyTwo and a constructor that requires values for all properties. Along with equality operators, deconstructors and a ToString() implementation that returns all properties in the form of a JSON string.
I am enabling C# 8.0 Nullable Reference Types on a .NET Core 3.0 project. The project uses Entity Framework Core 3.0 to access database.
The following is a data model whose Title should not be null.
public class Vehicle
{
public int Id { get; private set; }
public string Title { get; private set; }
// Entity Framework Core is instructed to bind to the private _drivers field in a configuration builder
private readonly List<Driver> _drivers = new List<Driver>();
public IReadOnlyCollection<Driver> Drivers => _drivers.AsReadOnly();
private Vehicle()
{
}
public Vehicle(string title)
{
this.Title = title;
}
public void AddDriver(string name)
{
this._drivers.Add(new Driver(name));
}
}
// A foreign column is defined in a configuration builder
public class Driver
{
public int Id { get; private set; }
public string Name { get; private set; }
private Driver()
{
}
public Driver(string name)
{
this.Name = name;
}
}
Own code is supposed to use the public constructors only while the private constructors are there just to allow Entity Framework Core and (potentially also) serialization to bind values from database to these classes/models. The public constructor might have different structure, list and types of arguments than which properties the model has (for example, it might also contains arguments for the first required child, it might have some arguments optional etc.).
However, the compiler generates CS8618 Non-nullable field is uninitialized. Consider declaring as nullable. on the private constructors.
I am able to disable CS8616 for the private constructors by #pragma warning disable CS8618 but I do not consider that as a good idea.
How it is supposed to use C# 8.0 Nullable Reference Types in this scenario?
Or is my model bogus or violates best practices - how to do it properly?
Unfortunatelly, I have found not relevant docs or guidance.
There is no proper way to handle non-nullable navigational properties.
Documentation suggests two ways and both are not type safe. Use a
backing field and throw InvalidOperationException. It is unclear how
it differs from doing nothing and have a NullReferenceException
Suppress it with null forgiving operator
Official documentation link: https://learn.microsoft.com/en-us/ef/core/miscellaneous/nullable-reference-types#non-nullable-properties-and-initialization
I agree with you- pragma blocks are ugly. Instead, I would assign the null forgiving operator to the non-nullable reference type inside the default constructor, like so:
private Vehicle()
{
Title = null!;
}
This is much cleaner and more expressive than initializing the property with said operator inline like so:
public string Title { get; private set; } = null!;
The latter solution reads as "I know Title is not null regardless of scenario" which effectively negates the benefit of non-nullable reference types since you lose all of your design time checks. The former reads as "I know Title is not null in this specific scenario", so compiler warnings continue to be issued elsewhere if you miss an assignment.
From the MS Docs for Entity types with constructors
When EF Core creates instances of these types, such as for the results
of a query, it will first call the default parameterless constructor
and then set each property to the value from the database. However, if
EF Core finds a parameterized constructor with parameter names and
types that match those of mapped properties, then it will instead call
the parameterized constructor with values for those properties and
will not set each property explicitly.
Perhaps it is worth creating a private ctor with the parameter needed for those properties and see if the Framework will then call that and work?
Also disabling warnings is not a good idea unless you are fully 100% confident that it is ok to disable it.
I am trying C# 8.0 out, and I want to enable the null reference checking for the entire project. I am hoping I can improve my code design, and without disabling the nullability context in any code scopes.
I encountered a problem when I deserialize an object graph. The objects have references with one another but, for the final user view, all references in the object graph must have a value.
In other words, during the deserialization process, references may be null, but after all objects have finished loading, a final process will link all of the objects together, thus resolving those null references.
Workarounds
I have been able to address this using a few different techniques, and they each work as expected. They also expand the code considerably, however, by introducing a lot of extra scaffolding.
Option #1: Shadow Class
For example, I tried writing a paired class for each kind of object, using these as an intermediate object during deserialization. In these paired classes, all reference are allowed to be null. After deserialization completes, I copy all fields from these classes and convert them to the real object. Of course, with this approach, I need write a lot of extra code.
Option #2: Shadow Members
Alternatively, I tried to put a nullable field and a non-nullable property. This is similar to the previous approach, but I'm using paired members instead of paired classes. Then I add an internal setter for each field. This approach has less code than the first, but it still increases my code base considerably.
Option #3: Reflection
Traditionally, without considering performance, I would have managed deserialization using reflection so that there’s almost has no extra code on a per class basis. But writing my own parsing code has some benefits—for example, I can output more useful error messages including tips on how callers can resolve issues.
But when I introduce the nullable fields, my parsing code increases considerably—and with the sole purpose of satisfying the code analysis.
Sample Code
For the sake of demonstration, I simplified the code as much as possible; my actual classes obviously do much more than this.
class Person
{
private IReadOnlyList<Person>? friends;
internal Person(string name)
{
this.Name = name;
}
public string Name { get; }
public IReadOnlyList<Person> Friends => this.friends!;
internal SetFriends(IReadOnlyList<Person> friends)
{
this.friends = friends;
}
}
class PersonForSerialize
{
public string? Name { get; set; }
public IReadOnlyList<string> Friends { get; set; }
}
IReadOnlyList<Person> LoadPeople(string path)
{
PersonForSerialize[] peopleTemp = LoadFromFile(path);
Person[] people = new Person[peopleTemp.Count];
for (int i = 0; i < peopleTemp.Count; ++i)
{
people[i] = new Person(peopleTemp[i].Name);
}
for (int i = 0; i < peopleTemp.Count; ++i)
{
Person[] friends = new Person[peopleTemp[i].Friends.Count];
for (int j = 0; j < friends.Count; ++j)
{
string friendName = peopleTemp[i].Friends[j];
friends[j] = FindPerson(people, friendName);
}
people[i].SetFriends(friends);
}
}
Question
Is there a way to satisfy the null reference checking in C# 8.0 for properties that are only temporarily null during deserialization without introducing a lot of extra code for every class?
You’re concerned that while your objects aren't intended to have null members, those members will inevitably be null during the construction of your object graph.
Ultimately, this is a really common problem. It affects, yes, deserialization, but also the creation of objects during e.g., mapping or data binding of e.g. data transfer objects or view models. Often, these members are to be null for a very brief period between constructing an object and setting its properties. Other times, they might sit in limbo during a longer period as your code e.g. fully populates a dependency data set, as required here with your interconnected object graph.
Fortunately, Microsoft has addressed this exact scenario, offering us two different approaches.
Option #1: Null-Forgiving Operator
The first approach, as #andrew-hanlon notes in his answer, is to use the null-forgiving operator. What may not be immediately obvious, however, is that you can use this directly on your non-nullable members, thus entirely eliminating your intermediary classes (e.g., PersonForSerialize in your example). In fact, depending on your exact business requirements, you might be able to reduce your Person class down to something as simple as:
class Person
{
internal Person() {}
public string Name { get; internal set; } = null!;
public IReadOnlyList<Person> Friends { get; internal set; } = null!;
}
Option #2: Nullable Attributes
Update: As of .NET 5.0.4 (SDK 5.0.201), which shipped on March 9th, 2021, the below approach will now yield a CS8616 warning. Given this, you are better off using the null-forgiving operator outlined above.
The second approach gives you the same exact results, but does so by providing hints to Roslyn's static flow analysis via nullable attributes. These require more annotations than the null-forgiving operator, but are also more explicit about what's going on. In fact, I actually prefer this approach just because it's more obvious and intuitive to developers otherwise unaccustomed to the syntax.
class Person
{
internal Person() {}
[NotNull, DisallowNull]
public string? Name { get; internal set; };
[NotNull, DisallowNull]
public IReadOnlyList<Person>? Friends { get; internal set; };
}
In this case, you're explicitly acknowledging that the members can be null by adding the nullability indicator (?) to the return types (e.g., IReadOnlyList<Person>?). But you're then using the nullable attributes to tell consumers that even though the members are marked as nullable:
[NotNull]: A nullable return value will never be null.
[DisallowNull]: An input argument should never be null.
Analysis
Regardless of which approach you use, the end results are the same. Without the null-forgiving operator on a non-nullable property, you would have received the following warning on your members:
CS8618: Non-nullable property 'Name' is uninitialized. Consider declaring the property as nullable.
Alternatively, without using the [NotNull] attribute on a nullable property, you would have received the following warning when attempting to assign its value to a non-nullable variable:
CS8600: Converting null literal or possible null value to non-nullable type.
Or, similarly, upon trying to call a member of the value:
CS8602: Dereference of a possibly null reference.
Using one of these two approaches, however, you can construct the object with default (null) values, while still giving downstream consumers confidence that the values will, in fact, not be null—and, thus, allowing them to consume the values without necessitating guard clauses or other defensive code.
Conversely, when using either of these approaches, you will still get the following warning when attempting to assign a null value to these members:
CS8625: Cannot convert null literal to non-nullable reference type.
That's right: You'll even get that when assigning to the string? property because that's what the [DisallowNull] is instructing the compiler to do.
Conclusion
It’s up to you which of these approaches you take. As they both yield the same results, it’s a purely stylistic preference. Either way, you’re able to keep the members null during construction, while still realizing the benefits of C#’s non-nullable types.
If I understand correctly, your question boils down to:
How do I avoid compiler warnings
CS8618: Non-nullable property 'Name' is uninitialized. Consider declaring the property as nullable.
for simple model classes which are used for serialization?
You can solve the problem by creating a default constructor for which you suppress the warning. Now you want to make sure that this constructor is only used by your deserialization routine (e.g. System.Text.Json or Entity Framework). To avoid unintentional use add annotation [Obsolete] with parameter error=true which would raise compiler error CS0618.
As code:
public class PersonForSerialize
{
#pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
[Obsolete("Only intended for de-serialization.", true)]
public PersonForSerialize()
#pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable.
{
}
// Optional constructor
public PersonForSerialize(string name, IReadOnlyList<string> friends)
{
Name = name;
Friends = friends;
}
public string Name { get; set; }
public IReadOnlyList<string> Friends { get; set; }
}
Note1: You can let Visual Studio auto-generate the optional constructor using a quick action.
Note2: If you really mean to use the constructor marked as obsolete, you need to remove the error=true parameter. Now you can suppress the warning when calling the parameter-less constructor via #pragma warning disable CA1806.
While certainly highlighted due to non-nullable defaults in C# 8, this is really a common 'circular dependency' problem that has always existed with interdependent construction.
As you found, one standard solution is to use a restricted setter. With C# 8, you may want to use a 'null-forgiving' null! during deserialization of the object graph - allowing you to differentiate an unconstructed set from a valid empty set, and minimize allocation.
Example:
class Person
{
internal Person(string name, IReadOnlyList<Person> friends)
{
Name = name; Friends = friends
}
public string Name { get; }
public IReadOnlyList<Person> Friends {get; internal set;}
}
class SerializedPerson { ... } // Class no longer specifically required.
IEnumerable<Person> LoadPeople(string path)
{
var serializedPeople = LoadFromFile(path);
// Note the use of null!
var people = serializedPeople.Select(p => new Person(p.Name, null!));
foreach(var person in people)
{
person.Friends = GetFriends(person, people, serializedPeople);
}
return people;
}
I'm not sure how you would serialise your graph structure without Name+IdsOnly class especially if a person has plenty properties, but this is out of scope.
Nullability of Friends
Nulls in Friends could be addressed by always having the list.
For example:
public List<Person> Friends { get; set; } = new List<Friends>();
Partly populated objects that look like they're null safe
If you're using Json.NET you could take advantage of JsonConstructor.
Please note with this approach you can end up with null in Person unless you protect against it in the constructor.
using Newtonsoft.Json;
class Person
{
[JsonConstructor]
internal Person(
string name,
List<Person> friends)
{
Name = name; // Can end up being null if left without '?? "No name"';
Friends = friends ?? new List<Person>();
}
public string Name { get; }
public List<Person> Friends { get; set; }
public void AddFriends(IEnumerable<Person> friends)
{
Friends.AddRange(friends);
}
}
This should handle all kinds of data:
Deserialise<Person>("{}");
Deserialise<Person>("{ 'Name': 'John'}");
Deserialise<Person>("{ 'Name': 'John', 'Friends': [] }");
Deserialise<Person>("{ 'Name': 'John', 'Friends': [ {'Name': 'Jenny'}]}");
Deserialise<Person>("{ 'Friends': [{'Name': 'Jenny'}]}");
All above examples should produce a Person object. You could then do validation and fill in the missing details.
I have a private class that looks like this:
private class PocoUserWithResourceId
{
public USER User;
public string ResourceId;
}
I do things with this class (within the same encapsulating public class), like:
var uQuery = from u in db.USERS.All()
select new PocoUserWithResourceId {User = u, ResourceId = arv.Resource_Id};
And I'm getting the warning:
Field 'PocoUserWithResourceId.ResourceId' is never assigned to, and
will always have its default value null
What am I missing? I'm assigning the value in my LINQ to SQL code.
Is it just because I'm assigning property values during the
declaration that the compiler doesn't see the fact that I'm using
them?
No, that's just because you're assigning field values, not property values ...
You have choice between 2 good practices :
- Use a constructor
- Use accessors (properties)
You can temporarily disable the warning for the specific case using #pragma
// turn it off
#pragma warning disable 0649
private class Foo
{
public string FieldName
}
// turn it back on
#pragma warning restore 0649
To figure out what the error number is, examine the raw output or right click the warning and choose Show Error Help. You'll find the error buried in the URL (CS0649) even though the page itself has nothing to do with the warning.