Вынуждены использовать mutable для чтения Excel ThisWorkbook.Names?

Я пытаюсь получить данные в именованном диапазоне Excel для надстройки на основе F #. Я хочу иметь возможность использовать именованные диапазоны в любом месте книги, а не только на конкретном листе.

let xlRange (xl:Microsoft.Office.Interop.Excel.Application, name:string) =
    let name_list = xl.ThisWorkbook.Names:Microsoft.Office.Interop.Excel.Names
    let mutable result=null
    for n in name_list do
        let nn = n :?> Microsoft.Office.Interop.Excel.Name
        if nn.Name = name then
            let range=nn.RefersToRange
            result <- range.Value2 :?> obj[,]
    result

Приведенный выше код работает, но мне он не нравится, потому что мне пришлось использовать изменяемый и императивный стиль. Проблема в том, что коллекция Excel.Names ведет себя не очень хорошо. Например

let name_seq = Seq.toList name_list

дает

Тип "Имена" несовместим с типом "seq‹'a>"

Есть ли более идиоматический способ F # сделать это?


person Paul Whiting    schedule 07.07.2012    source источник
comment
Попробуйте Seq.toList (Seq.cast name_list), возможно, даже укажите тип (например, let name_seq : ... = ...).   -  person Ramon Snir    schedule 07.07.2012


Ответы (2)


Вы должны использовать Seq.cast для приведения name_list к типизированной последовательности.

Преимущество очевидно; у вас лучше совместимость с F#, и вместо этого вы можете использовать функции высокого порядка в модуле Seq императивного цикла for.

let xlRange (xl: Microsoft.Office.Interop.Excel.Application, name: string) =
    xl.ThisWorkbook.Names
    |> Seq.cast<Microsoft.Office.Interop.Excel.Name> 
    |> Seq.tryPick (fun n -> if n.Name = name 
                             then Some (n.RefersToRange.Value2 :?> obj[,])
                             else None)

Тип возвращаемого значения теперь obj[,] option, что дает вам безопасность типов бесплатно.

person pad    schedule 07.07.2012
comment
Спасибо, это то, что я пытался сначала, но я получаю the type 'Names' is not compatible with the type 'IEnumerable' - person Paul Whiting; 09.07.2012

Я не мог использовать Seq. вещи напрямую из-за несовместимых типов. Я сделал эту функцию, которая предназначена для преобразования коллекции в список F #, который я мог бы затем обработать, как указано выше. Он скомпилирован нормально, но я не тестировал, потому что...

let xlNamesToList names =
    let rec xlNameList_r (names:Microsoft.Office.Interop.Excel.Names) idx =
        if idx>names.Count then // should this be >= ?
            []
        else
            names.Item(idx)::xlNameList_r names (idx+1)
    xlNameList_r names 0

... затем я нашел более простой способ сделать это напрямую:

let xlRange (xl:Microsoft.Office.Interop.Excel.Application, name:string) =
    try
        let r=xl.ThisWorkbook.Names.Item(name :> obj).RefersToRange
        Some(r.Value2 :?> obj[,])
    with
        | _ -> None

Спасибо за помощь, ребята!

person Paul Whiting    schedule 09.07.2012