Реализация интерфейсов C # со ссылочными типами, допускающими значение NULL, в F #

Я пытаюсь изучить F # путем преобразования существующего решения .NET Core на C # по одному проекту за раз. В настоящее время у меня есть интерфейс на C # со ссылочными типами, допускающими значение NULL:

public interface IVehicle {
    public int GetWheels();
    public string? GetLicensePlate();
}

И этот интерфейс реализован в ряде других проектов, зависящих от этого. Я пытаюсь преобразовать один из них, но если я попытаюсь

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()

Я получаю сообщение об ошибке:

Ожидалось, что это выражение будет иметь тип 'string', но здесь тип 'Nullable ‹string›'

Похоже, что это не влияет на типы значений, поэтому я предполагаю, что это как-то связано с тем, что string является ссылочным типом.

Что мне делать, чтобы решить эту проблему? Предположительно, я мог бы переписать базовый интерфейс, чтобы использовать F # и, следовательно, параметры, но есть другие проекты C #, которые реализуют интерфейс, и я не хочу, чтобы мне приходилось переписывать все решение за один раз. Или я совершенно неправильно делаю F #?


person waiwai933    schedule 18.04.2020    source источник


Ответы (1)


Это путаница между ссылками C # 8, допускающими значение NULL, и типами значений, допускающими значение NULL, иначе Nullable<T>. Если вы посмотрите определение Nullable<T>, вы обнаружите:

public struct Nullable<T> where T : struct

что означает, что это только для типов значений. int? - это сокращение от Nullable<int>. Это отличается от ссылок, допускающих значение NULL.

Модификатор допустимости значения NULL для ссылочных типов не вводит новый тип. Ссылочные типы по-прежнему допускают значение NULL, и компиляция string? приводит к тому, что IL остается только System.String.

Разница на уровне IL заключается в том, что измененные типы, допускающие значение NULL, украшаются символом NullableAttribute.

Другими словами, это просто конструкция компилятора, невидимая для F #.

match LicensePlateService.GetLicencePlate(serialNumber) with
| Some(x) -> x
| None -> null

будет правильной, хотя и неидиоматической заменой.

person Asti    schedule 18.04.2020