Sergej Andrejev
Sergej Andrejev

Reputation: 9403

Not nullable types

Is there a way to create a non nullable type in C# (like DateTime or TimeSpan).?

Also is there a way (an attribute maybe) to enforce that not null arguments wouldn't be passed to methods and properties without adding

if(arg1 == null)
{
   throw new ArgumentNullException("this attribute is null")
}

Upvotes: 14

Views: 9898

Answers (9)

robbie fan
robbie fan

Reputation: 686

YES! C# 8.0 introduced non-nullable reference types: https://learn.microsoft.com/en-us/dotnet/csharp/nullable-references

string message = null;

// warning: dereference null.
Console.WriteLine($"The length of the message is {message.Length}");

var originalMessage = message;
message = "Hello, World!";

// No warning. Analysis determined "message" is not null.
Console.WriteLine($"The length of the message is {message.Length}");

// warning!
Console.WriteLine(originalMessage.Length);

This is enabled by default on new projects. If you update the .NET version of an existing project, this won't be automatically enabled, but you can enable it in Project -> Properties -> Nullable.

Upvotes: 1

Esge
Esge

Reputation: 180

As for the second question, here is an idea inspired by Nullable<T>.

A method with null-checked arguments would look like:

void Foo(NotNull<string> s)
{
    var x = $"{s}";
    var i = int.Parse(s);
}

Usage of NotNull<T> isn't limited to method arguments. And it would be certainly nice if the language has some syntactic sugar for it in the future, e.g. Foo(string! s).

public struct NotNull<T> where T : class
{
    private T valueField;

    public NotNull(T value)
    {
        this.valueField = value;
        this.CheckNotNull(value);
    }

    public T Value => this.valueField;

    public static implicit operator T(NotNull<T> t)
    {
        return t.Value;
    }

    public static implicit operator NotNull<T>(T t)
    {
        return new NotNull<T>(t);
    }

    public override bool Equals(object other)
    {
        return this.Value.Equals(other);
    }

    public override int GetHashCode()
    {
        return this.Value.GetHashCode();
    }

    public override string ToString()
    {
        return this.Value.ToString();
    }

    private void CheckNotNull(T value)
    {
        if (value == null)
        {
            throw new InvalidOperationException($"Value cannot be null");
        }
    }
}

Upvotes: 1

nawfal
nawfal

Reputation: 73163

Of course you can write your own value types (enum and struct) which can't be null (unless made nullable).

As for the second part, you can have a generic parameter and a constraint of accepting only value types, which means argument can not be null - not very useful considering vast majority of cases we use class.

public static void Do<T>(T arg1) where T : struct
{
    //both struct and enum goes here.
}

Upvotes: 0

xdhmoore
xdhmoore

Reputation: 9876

In addition to the AOP solutions mentioned, Enterprise Library offers this in their validation block. http://msdn.microsoft.com/en-us/library/ff953182(v=pandp.50).aspx

Upvotes: 2

Dimitri C.
Dimitri C.

Reputation: 22496

You are right: this is a shortcoming in C# compared to C++. This is a shame, because 95% of all parameters I pass to functions are non-null pointers. In C++, you can add compiler-checked documentation indicating which pointers are ensured to point to something.

Upvotes: 4

Marc Gravell
Marc Gravell

Reputation: 1062492

The null-checking you refer to will be easier in .NET 4.0 / C# 4.0 via code-contracts, which does pretty much what you want.

Structs are already non-nullable, but don't go creating your own structs like crazy - you rarely need them (classes are far more common). There is no real concept of a "non-nullable class"; people have proposed syntax changes like:

void Foo(string! arg1) {...}

which would have the compiler do the non-null check on arg1 - but in reality, code-contracts does this and more. There are some things you can do in PostSharp, but it probably isn't worth the hastle.

One other thought on a non-nullable class (and one of the reasons they aren't implemented); what would default(T) be for a non-nullable class? ;-p The spec demands that default(T) is well defined...

Upvotes: 11

driis
driis

Reputation: 164281

A non-nullable type is a ValueType, in other words a struct. A struct cannot be null, so an example would be:

public struct MyStruct {}

There is no built-in way of ensuring that null is not passed as a parameter to a method (unless the type of the parameter is a ValueType). I have seen people create extension methods for doing a simpler (ie. less code) assertions on whether a parameter is null, this might be an option for you. On the other hand, the check is short to begin with; and the intent of the check is very clear. That might not be the case if you use a custom method of checking.

C# 4.0 will add better options for doing this kind of programming by contract, but is not available yet. As pointed out in another answer PostSharp is an option for doing what you want. PostSharp works by adding a post-compilation step where extra code is added.

There are some options for statically checking whether null might be passed, however. For example, ReSharper lets you decorate your own method parameters with a [NotNull] attribute, and ReSharper will issue warnings at compile time if it can determine that the parameter might be null. Of course this only warns you about (potentially) bad coding practice, it is not a runtime check and should not be used as such.

Upvotes: 6

Anton Gogolev
Anton Gogolev

Reputation: 115691

DateTime and TimeSpan are not-nullable since they are structs rather than classes.

As for your second question, there is no standard way you can do this in C#. You can do this using PostSharp, which is an AOP framework, or with Spec#, which is a whole new language (an extension of C#) which allows for some of desired behavior.

Upvotes: 16

Gishu
Gishu

Reputation: 136593

Structs (value type) variables will never be null - that explains your DateTime case. So if your method params are C# structs, you can be sure they will never be null.
However if your method params are reference types, they can be null. I dont think you can do away with the null check as you've shown above in that case.

Upvotes: 1

Related Questions