2013-08-18 2 views
6

Я использую Microsoft.FSharp.Reflection.FSharpValue.MakeUnion, для этого в качестве параметров требуется Reflection.UnionCaseInfo и obj[] (которые могут быть пустыми).obj [] и string [] as parameters

При использовании функции string[] у меня возникает Type mismatch. Expecting a obj [] but given a string [] The type 'obj' does not match the type 'string'.

Простейший пример можно создать из этого происходит следующим образом (я тест обернуты вокруг этого, и он не компилируется из-за линии, отмеченной !!.

let one (a:obj[]) = a |> Array.map (fun o->printfn "%A" o) |> ignore 
one [|"a";"b";"c"|] // OK! 
let str = [|"a";"b";"c"|] //the equivalent of my function return 
one str//!!Type mismatch. 

Я не уверен, если я я должен был лить/преобразовать строку [] в obj [] или ... ну, если я просто делаю что-то еще неправильное, о чем я не знаю.

edit: актуальная проблема, как описано ниже

let split (by:string) (input:string) = System.Text.RegularExpressions.Regex.Split(input,by) 

let buildArgs content = 
match content with 
| "" -> [||] 
| _ -> content |> split " " //Type mismatch 

это то, что я использовал: есть ли лучший способ?

| _ -> content |> split " "|> Array.map (fun s->s:>obj)//make sure obj[] is returned 

Casting and Conversions (F#) в качестве ссылки

Я также попытался это

let buildArgs content :obj[] = ... // Type mismatch 

но также дает мне ошибку:

Type Mismatch on the last line of the function if I don't do the Array.map .

+0

@ phillip-trelford - «вы также можете изменить одну функцию для принятия любого массива объектов, например, пусть один (a: #obj [])» (удаляется вместе с моим «ответом» - возрождение как ценное) <- thank вы за это предложение. К сожалению, я не могу использовать его на 'FSharpValue.MakeUnion' (если я не ошибаюсь) – CodeBeard

+0

вы могли бы создать свою собственную функцию MakeUnion, которая вызывает FSharpValue.MakeUnion –

+1

Ответ Томаса, вероятно, будет моим дефолтом, также вы можете сократить { s -> s:> obj) 'to' box' –

ответ

5

Я думаю, что ваш нынешний подход прекрасен; иногда я нахожу что-то вроде [|for str in ... -> box str|], чтобы быть более читаемым, чем ... |> Array.map (fun str -> box str), но ваш пробег может отличаться. Что касается того, почему вы сталкиваетесь с этим, здесь есть две несколько тонкие проблемы.

Как следует из замечаний Фила Трелфорда, система типа .NET допускает, что string[] рассматривается как obj[] (хотя для этого из F # требуется повышение и понижение, даже если система типа .NET не такая уж строгая). По-моему, эта особенность системы типа - это мерзость, и я бы вообще избегал ее, хотя в этом случае она, вероятно, безопасна (для совпадения мнений о нежелательности ковариации массива см. Covariance and Contravariance in C#, Part Two: Array Covariance и Array covariance: not just ugly, but slow too).

Так что в целом, string[] не будет обрабатываться компилятором obj[]. Почему тогда все хорошо, когда вы проходите в [|"a"; "b"; "c"|]?Ответ здесь заключается в том, что в конкретном случае литералов массива компилятор позволяет типу выражения массива быть супертипом типа каждого элемента, если такой супертип можно вывести (например, потому что он ограничен obj[] сигнатурой другого метода, как в вашем случае). Однако это работает только в случае литералов массива (т. Е. Выражений формы [|e1; e2; ... |]).

+0

Это очень понятно - спасибо. В общем, я чувствую себя «на милость» системы типов, и мне приходится ее обходить *, что немного неправильно. – CodeBeard

+1

Я понимаю. Jut помните, что семантически массив строк действительно не является массивом объектов (хотя это может быть немного неинтуитивным). Я уверен, что разработчики .NET могли бы вернуться вовремя, чтобы ввести тип ReadOnlyArray и использовать его вместо регулярных массивов во многих местах по всей структуре (а строка ReadOnlyArrays действительно может быть безопасно обработана как объект ReadOnlyArrays). К сожалению, нам приходится иметь дело с наследием, которое у нас есть, бородавки и все такое. – kvb

+0

'(fun str -> box str)' => 'box'? –

4

Если вы определяете переменную в держать объект кт массив, то вы можете также использовать аннотацию типа и F # будет базовым типом строки автоматически к объектам:

let values : obj[] = [|"a";"b";"c"|] 

Вообще, если компилятор знает тип цели, прежде чем найти выражение (он выглядит слева направо), то он автоматически построит массив объектов, даже если литерал содержит строки. Это также относится к вызовам функций в вашем вопросе.

Однако, как только вы создаете значение типа string[], вам необходимо его каким-либо образом преобразовать в obj[] (как утверждают другие).

+0

Спасибо. Я попытался использовать это обозначение для функции, которая возвращает массив (* отредактировал вопрос, чтобы отразить *), но это дает мне то же исключение. У меня нет массива как 'let', он конвейер из шаблона. – CodeBeard