Реализация C# интерфейсов с обнуляемыми ссылочными типами в F # - PullRequest
1 голос
/ 19 апреля 2020

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

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

, я получаю ошибку:

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

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

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

1 Ответ

3 голосов
/ 19 апреля 2020

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

public struct Nullable<T> where T : struct

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

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

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

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

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

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

...