2016-11-18 10 views
2

Я пытаюсь вызвать C# функции уже существующей библиотеки (и у меня нет времени, чтобы порт всей библиотеки на F #)Interop с параметрами, передаваемых по иому

namespace ExportLib 
{ 

    public static class Xlsx 
    { 
     public static bool TestSave(string proposed, ref string filename, ref string save_log) { 

из F # кода

let getUserFile(proposed) : UserFile = 
    let mutable filename = "" 
    let mutable save_log = "" 
    match Xlsx.TestSave(proposed, ref filename, ref save_log) with 
    | true -> FileResult(filename) 
    | false -> ErrorMsg(save_log) 

предназначен для преобразования функции в алгебраические типы данных с целью сделать незаконные состояния unrepresentable.

type UserFile = 
    // The value here is the file path. 
| FileResult of string 
    // The value here is the error msg. 
| ErrorMsg of string 

Моя проблема заключается в том, что mutable F # filename остается неизменным, несмотря на это назначается в функции C# (та же проблема с out string вместо ref string)

ответ

4

В F # ref не является ключевым, но функция, создающая контрольная ячейка. Таким образом, Xlsx.TestSave(proposed, ref filename, ref save_log) передает две вновь созданные ячейки ячейки (указывающие на значения mutable string) в TestSave, которая, в свою очередь, изменяет ячейку ref, чтобы указать на то, что назначено string. К сожалению, это не видно извне, так как ничего не указывает на ячейки ref. Один подход:

let getUserFile(proposed) : UserFile = 
    let filename = ref "" 
    let save_log = ref "" 
    match Xlsx.TestSave(proposed, filename, save_log) with 
    | true -> FileResult(!filename) 
    | false -> ErrorMsg(!save_log) 

Как отметил @kvb вы также можете использовать

let getUserFile(proposed) : UserFile = 
    let mutable filename = "" 
    let mutable save_log = "" 
    match Xlsx.TestSave(proposed, &filename, &save_log) with 
    | true -> FileResult(filename) 
    | false -> ErrorMsg(save_log) 

и избавиться от ref с совсем так F# 4.0 simplified the use of mutables vs. ref.

Кроме того, я стараюсь избегать match ИНГ на простом bool, традиционный if then else короче:

let getUserFile(proposed) : UserFile = 
    let mutable filename = "" 
    let mutable save_log = "" 
    if Xlsx.TestSave(proposed, &filename, &save_log) then 
     FileResult(filename) 
    else 
     ErrorMsg(save_log) 

Очевидно, using out instead of ref еще лучше, но «... уже существующую библиотеку ...» у вас может не быть такого выбора.

+1

Правильно. Кроме того, вы должны иметь возможность сохранять декларации такими, какие они есть, и передавать ссылки с помощью '& filename' и' & save_log'. – kvb

2

Если вы используете out вместо ref на C# стороне, то вы должны быть в состоянии только сделать это вместо:

let getUserFile(proposed) : UserFile = 
    match Xlsx.TestSave proposed with 
    | true, filename, _ -> FileResult(filename) 
    | false, _, save_log -> ErrorMsg(save_log) 

, потому что конечные out параметры можно рассматривать как кортеж с фактическим типом результата.