I'm trying to create a type similar to Rust's Result or Haskell's Either and I've got this far:
public struct Result<TResult, TError>
where TResult : notnull
where TError : notnull
{
private readonly OneOf<TResult, TError> Value;
public Result(TResult result) => Value = result;
public Result(TError error) => Value = error;
public static implicit operator Result<TResult, TError>(TResult result)
=> new Result<TResult, TError>(result);
public static implicit operator Result<TResult, TError>(TError error)
=> new Result<TResult, TError>(error);
public void Deconstruct(out TResult? result, out TError? error)
{
result = (Value.IsT0) ? Value.AsT0 : (TResult?)null;
error = (Value.IsT1) ? Value.AsT1 : (TError?)null;
}
}
Given that both types parameters are restricted to be notnull, why is it complaining (anywhere where there's a type parameter with the nullable ? sign after it) that:
A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
?
I'm using C# 8 on .NET Core 3 with nullable reference types enabled.
Basically you're asking for something that can't be represented in IL. Nullable value types and nullable reference types are very different beasts, and while they look similar in source code, the IL is very different. The nullable version of a value type
Tis a different type (Nullable<T>) whereas the nullable version of a reference typeTis the same type, with attributes telling the compiler what to expect.Consider this simpler example:
That's invalid for the same reason.
If we constraint
Tto be a struct, then the IL generated for theGetNullValuemethod would have a return type ofNullable<T>.If we constraint
Tto be a non-nullable reference type, then the IL generated for theGetNullValuemethod would have a return type ofT, but with an attribute for the nullability aspect.The compiler can't generate IL for a method which has a return type of both
TandNullable<T>at the same time.This is basically all the result of nullable reference types not being a CLR concept at all - it's just compiler magic to help you express intentions in code and get the compiler to perform some checking at compile-time.
The error message isn't as clear as it might be though.
Tis known to be "a value type or non-nullable reference type". A more precise (but significantly wordier) error message would be:At that point the error would reasonably apply to our code - the type parameter is not "known to be a value type" and it's not "known to be a non-nullable reference type". It's known to be one of the two, but the compiler needs to know which.