.net F#转换为编译时未知的类型
如何铸造给定的obj列表.net F#转换为编译时未知的类型,.net,reflection,casting,f#,.net,Reflection,Casting,F#,如何铸造给定的obj列表 let l = [1. :> obj; 2. :> obj] 当编译时不知道原始类型(在本例中为float)时返回到float列表 我已经试过(表明我对此知之甚少:): 这是非常失败的 及 let castMe(ty:Type)(arr:obj列表)= 设m=typeof.GetMethod(“Cast”) 设m=m.MakeGenericMethod([| ty |]) m、 调用(null,[| arr |]):?>System.Collections
let l = [1. :> obj; 2. :> obj]
当编译时不知道原始类型(在本例中为float)时返回到float列表
我已经试过(表明我对此知之甚少:):
这是非常失败的
及
let castMe(ty:Type)(arr:obj列表)=
设m=typeof.GetMethod(“Cast”)
设m=m.MakeGenericMethod([| ty |])
m、 调用(null,[| arr |]):?>System.Collections.Generic.IEnumerable
设t=(l |>List.head).GetType();
l|>castMe t;;
它失败于:
错误FS0030:值限制。已将值“it”推断为
具有泛型类型
valit:Generic.IEnumerable这个没有语法,因为正如韦斯利·怀瑟所指出的那样,对于这样一个表达式,你是无能为力的。但是,由于您处理的是
Expr
值,因此可以使用Expr.concure
方法创建与所需内容等效的表达式树。您可以使用通过反射调用的帮助器类执行最初要求的操作:
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|])
i、 e.结果的动态类型为float list
(但静态类型为obj
),而原始输入的动态类型为obj list
为了有价值地使用结果,您需要一些关注区别的东西,但这样的代码肯定存在。假设您可以转换为“运行时类型”,您打算如何处理这个值?不能使用
运算符调用方法或访问数据,因为该类型在运行时而不是编译时已知。是否要使用反射来调用值的方法或属性?如果是,没有理由强制转换它。我正在尝试创建F#type提供程序,它将从字典中提供类似F#type的内容,并将这些字典列表作为类型成员。@WesleyWiser(如果这完全无关,请让我知道Klark,我“删除它”)@RubenBartelink谢谢,这个问题的背景很有帮助。在我看来,您的类型提供程序只需要生成一个表示字典的类型。通读这些教程给我的印象是,您不需要像您试图做的那样强制转换到运行时。实现类型提供程序的哪一部分让您陷入困境?很好。但是,是否也可以获得浮点列表的静态类型?唯一的方法是通过反射,或者如果您特别想查找浮点列表
,则通过显式类型测试-这是从动态类型到静态类型的两种方法。在Go
中的CastHelper
中,结果确实具有静态类型的float list
,因此一个选项是使该方法更长,并让它执行您实际想要对列表执行的操作。谢谢,这非常有用。您能告诉我一些关于如何使用Expr.concure的资源吗?@Klark-作为一个例子,Expr.concure(,typeof)
大致相当于float@@@>
。
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;;
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)
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]]"