A functional way to clean resources in F #

Hi, this is an example of how C # handles Inter interop resource management. source source :

Excel.Application app = null;
Excel.Workbooks books = null;
Excel.Workbook book = null;
Excel.Sheets sheets = null;
Excel.Worksheet sheet = null;
Excel.Range range = null;

try
{
    app = new Excel.Application();
    books = app.Workbooks;
    book = books.Add();
    sheets = book.Sheets;
    sheet = sheets.Add();
    range = sheet.Range["A1"];
    range.Value = "Lorem Ipsum";
    book.SaveAs(@"C:\Temp\ExcelBook" + DateTime.Now.Millisecond + ".xlsx");
    book.Close();
    app.Quit();
}
finally
{
    if (range != null) Marshal.ReleaseComObject(range);
    if (sheet != null) Marshal.ReleaseComObject(sheet);
    if (sheets != null) Marshal.ReleaseComObject(sheets);
    if (book != null) Marshal.ReleaseComObject(book);
    if (books != null) Marshal.ReleaseComObject(books);
    if (app != null) Marshal.ReleaseComObject(app);
} 

Personally, I believe that the code above is reasonable and necessary. But this does not work or F #. I ended up defining all these com variables at different levels of the nested try ... finally and try ... with and because the variable must be defined before trying to block the cleanup codes in both and in the finally block. This is very dirty.

How can I implement the same thing in F # correctly? Its a bit ironic, there are many examples on the Internet explaining how to use F # with interop as a way to demonstrate the power of F #. However, none of them says how to manage the cleaning of com resources.

.

+4
1

, try/catch , . /, , .

type FinalizationBuilder(oncreate, onfinal) =
  member __.Bind(m, f) = 
    oncreate(box m)
    try
      try
        f m
      with ex ->
        Choice2Of2 ex.Message
    finally
      onfinal(box m)
  member __.Return(m) = Choice1Of2 m
  member __.Zero() = Choice1Of2()

COM, COM-, .

let com = new FinalizationBuilder(ignore, System.Runtime.InteropServices.Marshal.ReleaseComObject >> ignore)

:

[<EntryPoint>]
let main _ = 
  com { 
    let! app = new Excel.Application()
    let! books = app.Workbooks
    let! book = books.Add()
    // ...
    app.Quit()
  } |> ignore
  0

excel, printfns.

let demo = new FinalizationBuilder(printfn "Created %A", printfn "Released %A")

[<EntryPoint>]
let main _ = 
  demo { 
    let! x = 1
    let! y = 2
    let! z = 3
    return x + y + z
  } |> printfn "Result: %A"
  0

// Created 1
// Created 2
// Created 3
// Released 3
// Released 2
// Released 1
// Result: Choice1Of2 6

:

[<EntryPoint>]
let main _ = 
  demo { 
    let! x = 1
    let! y = 2
    let! z = failwith "boom"
    return x + y + z
  } |> printfn "Result: %A"
  0

// Created 1
// Created 2
// Released 2
// Released 1
// Result: Choice2Of2 "boom"

, , , . GC.Collect(); GC.WaitForPendingFinalizers() , : fooobar.com/questions/139047/...

+6

Source: https://habr.com/ru/post/1651623/


All Articles