Reputation: 14559
I'm trying to learn F# by converting an existing .NET Core solution in C# over, one project at a time. I currently have an interface in C# with nullable reference types:
public interface IVehicle {
public int GetWheels();
public string? GetLicensePlate();
}
And this interface is implemented in a number of other projects which depend on this one. I'm trying to convert one of these over, but if I try
type Car(serialNumber: string) =
interface MyProjectInterfaces.IVehicle with
member this.GetWheels() = 4
member this.GetLicensePlate() =
match LicensePlateService.GetLicencePlate(serialNumber) with
| Some(x) -> System.Nullable(x)
| None -> System.Nullable()
I get the error:
This expression was expected to have type 'string' but here has type 'Nullable<string>'
This doesn't seem to affect value types, so I'm assuming it's something to do with string
being a reference type.
What do I do to solve this? Presumably I could rewrite the underlying interface to use F# and thus options, but there are other C# projects that implement the interface and I don't want to have to rewrite the whole solution in one go. Or am I doing F# completely wrong?
Upvotes: 1
Views: 824
Reputation: 12667
This is a confusion between C# 8's nullable references and nullable value types, aka Nullable<T>
. If you look at the definition of Nullable<T>
, you'll find:
public struct Nullable<T> where T : struct
which means it's only for value types. int?
is short for Nullable<int>
.
That's different from nullable references.
The nullability modifier for reference types doesn’t introduce a new type. Reference types are still nullable and compiling
string?
results in IL that’s still justSystem.String
.The difference at the IL level is the decoration of nullable modified types with a
NullableAttribute
.
In other words, it's just a compiler construct - one which isn't visible to F#.
match LicensePlateService.GetLicencePlate(serialNumber) with
| Some(x) -> x
| None -> null
will be the correct, albeit non-idiomatic replacement.
Upvotes: 3