2017-02-01 19 views
10

Dường như với tôi rằng một số thuộc tính của loại tùy chọn F # không hiển thị từ các dự án C#. Bằng cách kiểm tra các loại, tôi có thể thấy nhiều hơn hoặc ít hơn lý do, nhưng tôi không thực sự hiểu chính xác những gì đang xảy ra, tại sao những lựa chọn này đã được thực hiện hoặc cách tốt nhất để phá vỡ vấn đề.Tại sao một số thuộc tính (ví dụ: IsSome và IsNone) cho FSharpOption không hiển thị từ C#?

Dưới đây là một số đoạn trích chứng minh sự cố. Tôi có một giải pháp VS2015 có chứa hai dự án, một dự án C# và một dự án F #. Trong # dự án F, tôi có một lớp được định nghĩa như sau:

type Foo() = 

    member this.Bar() = Some(1) 

Hơn nữa, trong F # tôi có thể viết một cái gì đó như thế này:

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

Vì vậy, có thể thấy rằng các loại tùy chọn có thuộc tính được đặt tên IsNone. Bây giờ, trong dự án C#, tôi có một tham chiếu đến .dll được biên dịch từ dự án F #. Điều này cho phép tôi viết ví dụ:

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

Biến số optionTypeFSharpOption<int>. Như tôi đã lưu ý ở trên, khi tôi sử dụng các loại tùy chọn trong các dự án F #, tôi thường có quyền truy cập ví dụ như các thuộc tính IsSomeIsNone. Tuy nhiên, khi tôi cố gắng viết một cái gì đó như optionType.IsNone, tôi nhận được lỗi CS1546 "Thuộc tính, chỉ mục hoặc sự kiện ... không được hỗ trợ bởi ngôn ngữ". Trong sự phù hợp với điều này, Intellisense không phát hiện tài sản:

Intellisense does not detect the IsSome and IsNone properties

Bây giờ, khi kiểm tra các loại FSharpOption, tôi có thể thấy rằng IsNone và IsSome "tài sản" xuất hiện phương pháp như tĩnh:

FSharpOption class signature from C#

Mặt khác, khi tôi kiểm tra các loại từ F #, tôi thấy sau thay vì:

FSharpOption class signature from F#

Ở đây, "sự tồn tại" của các thuộc tính IsSomeIsNone là điều hiển nhiên. Di chuyển con trỏ qua các thuộc tính này, VS2015 cho tôi lưu ý sau: "Kiểu chứa có thể sử dụng 'null' làm giá trị biểu diễn cho trường hợp công đoàn vô giá trị của nó. Thành viên này sẽ được biên dịch thành một thành viên tĩnh." Đây là lý do tại sao các thuộc tính không có sẵn ngoại trừ các phương thức tĩnh (như được lưu ý bởi lukegv và Fyodor Soikin).

Vì vậy, tình huống có vẻ như sau: Loại FSharpOption được biên dịch không có bất kỳ thuộc tính IsNone và IsSome nào. Một cái gì đó đang diễn ra đằng sau hậu trường trong F # để kích hoạt chức năng mô phỏng các thuộc tính này.

Tôi biết rằng tôi có thể giải quyết vấn đề này bằng cách sử dụng OptionModule trong Microsoft.FSharp.Core. Tuy nhiên, có vẻ như chức năng này là một sự lựa chọn có ý thức của các kiến ​​trúc sư của thư viện lõi F #. Những lý do cho sự lựa chọn là gì? Và đang sử dụng OptionModule giải pháp đúng, hoặc có cách nào tốt hơn để sử dụng loại FSharpOption<T> từ C#?

Trả lời

10

Điều này phải làm với cách option được biên soạn. Giá trị Some được biên dịch đơn giản như tạo một thể hiện của lớp và gói giá trị trong đó. Nhưng giá trị None không thực sự là giá trị, chúng chỉ là null.

Hãy thử điều này:

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 

(đây cũng là lý do mà các None giá trị will show up as null in the debugger's Watch window)

Đây là một tối ưu hóa mà tiết kiệm rất nhiều chu kỳ khi chạy. (và bạn cũng có thể sử dụng nó cho các loại hình công đoàn của mình bằng cách áp dụng CompilationRepresentationFlags.UseNullAsTrueValue)

Bây giờ, vì một số giá trị thuộc loại này có thể là null, bạn không thể sử dụng thuộc tính hoặc phương pháp trên các giá trị này. Nếu giá trị xảy ra là null, bạn sẽ chỉ gặp sự cố. Đó là lý do tại sao bạn nên luôn sử dụng OptionModule cho tất cả các hoạt động.

Đối với lý do tại sao các thuộc tính này không hiển thị trong intellisense - đó là vì chúng là static. Mặc dù tôi không chắc tại sao họ lại có mặt ở đó. Có lẽ một tạo tác trình biên dịch.

+3

Cảm ơn, thực tế là các giá trị None thực sự là một giải thích tốt về lý do tại sao các thuộc tính IsNone và IsSome bị xóa. Tôi đã chỉnh sửa các câu hỏi một chút để bao gồm của bạn và nhận xét của lukegv rằng trong lớp biên dịch, các "tài sản" là tĩnh. –

+0

Sooo ... Bạn vẫn không nhận được cơ chế và lý do? Còn gì nữa không rõ? –

+0

Không, nó có ý nghĩa, cảm ơn :-) –

2

Tôi không thạo với F #, nhưng vì nó là tất cả CLR, câu trả lời của tôi là từ một C# điểm:

Trong định nghĩa lớp được tạo ra, cả hai IsNoneIsSome là tĩnh và do không thể được truy cập thông qua cá thể optionType (không qua IntelliSense, cũng như trong mã). Thuộc tính Value không tĩnh và có thể truy cập được.

Các vấn đề liên quan