ExcelDna F# 和可选参数

ExcelDna F# and optional arguments

对于标量(即非类数组)可选参数,我会使用这种模式:

[<ExcelFunction(Category= "Test", Description= "Test optional arguments.")>]
let test_test1 ([<ExcelArgument(Description= "Optional. This is a double. Default is 42.0.")>] arg1 : obj) : double = 
    match arg1 with
    | :? ExcelMissing -> 42.0  // the argument was missing
    | :? double as d  -> d     // the argument was a double
    | _               -> -1.0  // otherwise

我不确定此代码是否在 Excel-Dna / F# 中 "idiomatic" 但它似乎 "work".

但是我不确定如何处理可选的类似数组的参数。例如:

[<ExcelFunction(Category= "Test", Description= "Test optional arguments.")>]
let test_test2 ([<ExcelArgument(Description= "Optional. This is a double. Default is [42, 42].")>] arg1 : obj[]) : double[] = 
    match arg1.[0] with
    | :? ExcelMissing -> [42.0; 42.0] |> List.toArray // the argument was missing OR it was an empty array
    | :? double as d  -> arg1 |> castToDouble         // the argument was an array and its first argument was a double
    | _               -> Array.empty                  // otherwise

以上似乎适用于大多数情况,但不允许正确处理边缘情况:例如,如果 arg1 是空数组。 (castToDouble 是自定义 obj[] -> double[] 转换函数)

在 F# / Excel-Dna 中处理 可选 双数组的正确/惯用方法是什么,然后我如何重写 test_test2?

=========== 编辑 ===

按照 Govert 的建议,我尝试了以下操作:

[<ExcelFunction(Category= "Test", Description= "Test optional arguments.")>]
let test_test3 ([<ExcelArgument(Description= "Optional. This is a double. Default is [42, 42].")>] arg1 : obj) : double[] = 
    match arg1 with
    | :? (double[]) as ds  -> [1.0; 2.0] |> List.toArray   // the argument was a array of double elements
    | :? ExcelMissing      -> [42.0; 42.0] |> List.toArray // the argument was missing OR it was an empty array
    | _                    -> Array.empty                  // otherwise        

...但不幸的是,当我传递一个双精度数组(或其他任何数组)时,我得到了一个 #NUM! 输出。只有当我什么都不传递时,我才能正确获得 [42.0, 42.0] 数组。

这涵盖了所有的可能性:


[<ExcelFunction("describes the input argument")>]
let describe(arg1 : obj) : string =
    match arg1 with
        | :? double as d        -> sprintf "Double: %f" d
        | :? string as s        -> "String: " + s
        | :? bool as b          -> sprintf "Boolean: %b" b
        | :? ExcelError as err  -> sprintf "ExcelError: %A" err
        | :? (obj[,]) as arr    -> sprintf "Array[%i, %i]" (Array2D.length1 arr) (Array2D.length2 arr)
        | :? ExcelEmpty         -> "<<Empty>>"
        | :? ExcelMissing       -> "<<Missing>>"
        | _                     -> "!? Unheard of ?!"