Компилятору 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. Таким образом, вы сможете отслеживать отзывы оттуда.