2017-02-01 6 views
10

Мне кажется, что некоторые свойства типа опции F # не видны из проектов C#. Проверяя типы, я вижу более или менее причину, но я не совсем понимаю, что именно происходит, почему эти выборы были сделаны или как лучше всего обойти проблему.Почему некоторые свойства (например, IsSome и IsNone) для FSharpOption не видны с C#?

Ниже приведены некоторые фрагменты, демонстрирующие проблему. У меня есть решение VS2015, содержащее два проекта, проект C# и проект F #. В # проекта F, у меня есть класс, определяемый следующим образом:

type Foo() = 

    member this.Bar() = Some(1) 

Кроме того, в F # Я могу написать что-то вроде этого:

let option = (new Foo()).Bar() 
let result = if option.IsNone then "Is none" else "Is some" 

Так может показаться, что тип параметра имеет свойство с именем IsNone. Теперь, в проекте C#, у меня есть ссылка на .dll, скомпилированный из проекта F #. Это позволяет мне писать, например.

var optionType = new Foo().Bar(); 

Переменная optionType является FSharpOption<int>. Как я уже отмечал выше, когда я использую типы опций в проектах F #, я обычно имею доступ, например, к объектам IsSome и IsNone. Однако, когда я пытаюсь написать что-то вроде optionType.IsNone, я получаю ошибку CS1546 «Свойство, индекс или событие ... не поддерживается языком». В согласовании с этим, Intellisense не обнаруживает свойство:

Intellisense does not detect the IsSome and IsNone properties

Теперь при проверке типа FSharpOption, я могу видеть, что IsNone и IsSome «Свойства» отображаются как статические методы:

FSharpOption class signature from C#

с другой стороны, когда я проверить тип из F #, я вижу следующие вместо:

FSharpOption class signature from F#

Здесь «существование» свойств IsSome и IsNone очевидно. Наводя курсор на эти свойства, VS2015 дает мне следующее примечание: «Содержащий тип может использовать« null »в качестве значения представления для своего случая с унифицированным объединением. Этот член будет скомпилирован как статический член». Именно по этой причине свойства недоступны, кроме как статические методы (как отмечают Лукев и Федор Сойкин).

Итак, ситуация выглядит так: Скомпилированный тип FSharpOption не имеет никаких свойств IsNone и IsSome. Что-то происходит за кулисами в F #, чтобы включить эмуляцию этих свойств.

Я знаю, что могу обойти это, используя OptionModule в Microsoft.FSharp.Core. Однако, похоже, что эта функциональность является сознательным выбором для архитекторов основной библиотеки F #. Каковы причины выбора? И использует OptionModule правильное решение, или есть лучший способ использовать тип FSharpOption<T> от C#?

ответ

10

Это связано с тем, как скомпилировано option. Значения Some скомпилированы просто как создание экземпляра класса и обертывание в нем значения. Но значения None не являются действительно значениями, они всего лишь null.

Попробуйте это:

let a: int option = Some 1 
let b: int option = None 
let a_isNull = obj.ReferenceEquals(a, null) // a_isNull = false 
let b_isNull = obj.ReferenceEquals(b, null) // b_isNull = true 

(это также является причиной того, что None значения will show up as null in the debugger's Watch window)

Это оптимизация, которая экономит много циклов во время выполнения. (и вы можете использовать его для своих собственных типов союзов тоже, применяя CompilationRepresentationFlags.UseNullAsTrueValue)

Теперь, поскольку некоторые значения этого типа могут быть null, вы не можете использовать свойства или методы для этих значений. Если значение будет null, вы просто потерпите крах. Вот почему вы всегда должны использовать OptionModule для всех операций.

Что касается того, почему эти свойства не отображаются в intellisense - это потому, что они static. Хотя я не уверен, почему они присутствуют там вообще. Возможно, артефакт компилятора.

+3

Спасибо, факт, что значения None действительно null, является хорошим объяснением того, почему свойства IsNone и IsSome удалены. Я немного отредактировал вопрос, чтобы включить ваше и замечание Lukegv о том, что в скомпилированном классе «свойства» являются статическими. –

+0

Sooo ... Вы все еще не получаете механику и причины? Что-нибудь еще неясно? –

+0

Нет, это имеет смысл, спасибо :-) –

2

Я не очень хорошо знаком с F #, но так как это все CLR, мой ответ из C# точки зрения:

В сгенерированном определении класса, как IsNone и IsSome являются статическими, и для этого не может доступ через экземпляр optionType (ни через IntelliSense, ни в код). Свойство Value не является статическим и может быть доступно.