2016-11-18 2 views
2

J'essaie d'appeler une fonction C# d'une bibliothèque déjà existante (et je ne suis pas le temps au port toute bibliothèque F #)Interop avec des paramètres passés par ref

namespace ExportLib 
{ 

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

d'un code 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) 

destiné à transformer la fonction en types de données algébriques avec l'objectif de rendre les États illégaux unrepresentable.

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

Mon problème est que le mutable F # filename reste inchangé malgré qu'il est affecté dans la fonction C# (même problème avec out string au lieu de ref string)

Répondre

4

En F # ref n'est pas un mot-clé, mais une fonction créant une cellule de référence. Xlsx.TestSave(proposed, ref filename, ref save_log) passe ainsi deux cellules ref erence nouvellement créées (pointant vers mutable string valeurs) dans TestSave qui à son tour change la cellule ref pour pointer vers string attribué. Malheureusement, ceci n'est pas observable de l'extérieur, car il n'y a rien qui pointe vers les cellules ref. Une approche est:

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) 

Comme indiqué par @kvb, vous pouvez également utiliser

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) 

et de se débarrasser de tout à fait ref s depuis F# 4.0 simplified the use of mutables vs. ref.

Aussi, j'essaie d'éviter match ing sur un simple bool, if then else traditionnelle est plus courte:

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) 

De toute évidence, using out instead of ref est encore mieux, mais pour "... une bibliothèque déjà existante ..." vous pourriez ne pas avoir ce choix.

+1

C'est vrai. Alternativement, vous devriez pouvoir conserver les déclarations telles qu'elles étaient et passer des références en utilisant '& filename' et' & save_log'. – kvb

2

Si vous utilisez out au lieu de ref sur le côté C#, alors vous devriez être en mesure de le faire à la place:

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

car fuite out paramètres peuvent être traités comme un tuple avec le type de résultat réel.