如何投射给定的obj列表。
let l = [1. :> obj; 2. :> obj]
当原始类型(在本例中为float)在编译时不知道时返回浮点列表?
我已经尝试过(表明我对此知之甚少:)):
let t = (l |> List.head).GetType();
l |> List.map (fun e -> e :?> t)
哪个失败了。
和
let castMe (ty : Type) (arr : obj list) =
let m = typeof<Enumerable>.GetMethod("Cast")
let m = m.MakeGenericMethod([|ty|])
m.Invoke(null, [|arr|]) :?> System.Collections.Generic.IEnumerable<_>
let t = (l |> List.head).GetType();
l |> castMe t;;
哪个失败了:
错误FS0030:值限制。值'it'已推断出来 有通用类型 val it:Generic.IEnumerable&lt;'_ a&gt;将'it'定义为一个简单的数据项,使其成为具有显式参数的函数,或者if 你并不打算将它作为通用的,添加一个类型注释。
=============================================
编辑:
我会尝试解释我想要实现的目标和迄今为止的目标,因为我可能根本没有采取正确的方法。
这是我用来保存我提供类型的数据的结构。
type public InnerData(query, table) =
...
member __.Data = data // map <string, obj list>
member __.Headers = headers // Dictionary <string, Type>
这是我的类型提供者的构造函数。
ty.AddMember(ProvidedConstructor([], InvokeCode = fun [] -> <@@ InnerData(queryParam, tableNameParam) :> obj @@>))
这就是我如何定义代表字典键的属性。看看评论。
do mdsTy.DefineStaticParameters([tableNameParam; queueryParam], fun tyName [| :? string as tableNameParam; :? string as queryParam |] ->
let ty = ProvidedTypeDefinition(
asm,
ns,
tyName,
baseType = Some(typeof<obj>))
let mdsInner = MdsData(mdsQueryParam, tableNameParam)
for header in mdsInner.Headers do
let columnName = header.Key
let columnType = header.Value
let arrayType = typedefof<IEnumerable<_>>.MakeGenericType(typeof<obj>)
// This works, but returns obj list. I would like to return a list of columnType that represents the downcasted version of arraytype.
let property = ProvidedProperty(columnName, arrayType,
GetterCode = fun [innerType] -> <@@ ((%%innerType:obj) :?> InnerData).Data.[columnName] @@>)
ty.AddMember(property)
在这里,我尝试使用上述方法(反射和:?&gt;)来投射数据,但没有任何运气。
答案 0 :(得分:3)
没有这方面的语法,因为正如Wesley Wiser指出的那样,无论如何你无法用这样的表达做任何事情。但是,由于您正在处理Expr
值,因此可以使用Expr.Coerce
方法创建与您想要的表达式树相当的表达式树。
答案 1 :(得分:2)
您可以使用通过反射调用的辅助类来执行您最初要求的操作:
type CastHelper<'t>() =
static member Go(xs : obj list) : 't list =
xs |> List.map (fun x -> x :?> 't)
let castList (xs : obj list) : obj =
let typ =
match xs with
| [] -> failwithf "Can't cast an empty list"
| x::xs -> x.GetType()
let doCast = typedefof<CastHelper<_>>.MakeGenericType([|typ|])
.GetMethod("Go")
doCast.Invoke(null, [|box xs|])
例如,您的样本数据:
> let xs = [1.0 :> obj ; 2.0 :> obj];;
val xs : obj list = [1.0; 2.0]
> let ys = castList xs;;
val ys : obj = [1.0; 2.0]
> xs.GetType().FullName;;
val it : string =
"Microsoft.FSharp.Collections.FSharpList`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
> ys.GetType().FullName;;
val it : string =
"Microsoft.FSharp.Collections.FSharpList`1[[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
即。结果的动态类型为float list
(但静态类型为obj
),而原始输入的动态类型为obj list
。
为了有价值地使用结果,你需要一些关心区别的东西,但这样的代码当然可以存在。