Компилятору F# требуется ссылка на проект, но метод является приватным

Компилятор F# выдает ошибку, говоря, что я должен добавить ссылку на проект, потому что тип, который я использую, имеет аргумент метода, который живет в этом проекте. Но этот метод является частным!

У меня есть следующая структура проекта:

Программа -> Библиотека -> Библиотека

SubLibrary содержит это:

namespace SubLibrary

type Widget = { Value: int }

Библиотека содержит это:

namespace Library

open SubLibrary

type Banana =
    { Value: int }

    member private x.TakeWidget (w: Widget) = ()

Программа содержит это:

open Library

[<EntryPoint>]
let main argv = 
    printfn "%A" argv

    let banana = { Value = 42 }
    0

Я получаю эту ошибку:

error FS0074:
The type referenced through 'SubLibrary.Widget' is defined in an assembly that is not referenced.
You must add a reference to assembly 'SubLibrary'

Но TakeWidget метод является частным!

Я пытался изменить Banana в класс, а не запись, но это не имело никакого значения.

В качестве эксперимента я создал C# версию библиотеки, которая называется CLibrary:

using SubLibrary;

namespace CLibrary {
    public class CBanana {
        int m_value;

        public CBanana(int value) {
            m_value = value;
        }

        private void TakeWidget(Widget w) {
        }
    }
}

Затем я изменил программу для использования CBanana вместо Banana:

open Library

[<EntryPoint>]
let main argv = 
    printfn "%A" argv

    let banana = CBanana 42
    0

Теперь я не получаю ошибку. Фактически, с C# я могу сделать этот метод общедоступным, и до тех пор, пока я не пытаюсь скомпилировать вызов, нет ошибки.

Почему компилятор настаивает на том, чтобы я добавил ссылку на SubLibrary? Конечно, я мог бы просто пойти дальше и сделать то, что мне велено, для спокойной жизни, но SubLibrary - это частная деталь реализации Library, которая не должна быть открыта для Program.

2 ответа

На самом деле, когда я попытался использовать класс вместо записи, он добился цели (F# 3.1):

type BananaClass (value:int) = 
    member private x.TakeWidget (w: Widget) = ()
    member x.Value = value

Вы также можете обойти это с записью - вам нужно переместить приватный элемент в отдельный модуль и использовать его в качестве дополнения типа:

type Banana = { Value: int }

module Ext =
    type Banana with
        member x.TakeWidget (w: Widget) = ()

Компилятор не будет жаловаться на отсутствующую зависимость, пока вы не откроете Ext модуль.

Я понятия не имею, почему компилятор жаловался в первую очередь. Вероятно, одна из его причуд. Я не нашел ничего серьезного в сгенерированном IL (кроме удивительного факта, что компилятор F# помечает как частные, так и внутренние члены как внутренние в IL - здесь это не имело никакого значения).

Действительно, для меня это выглядит как ошибка, которую я поднял здесь, https://github.com/Microsoft/visualfsharp/issues/86. Таким образом, вы сможете отслеживать отзывы оттуда.

Другие вопросы по тегам