Vag*_*lov 5 reflection f# discriminated-union
我的 F# 代码的某些函数接收装箱为对象的值,即使输入了基础值也是如此。如果该值是可区分联合,则无法将其拆箱回 F# 类型。这是一个简单的例子:
type Result<'TOk,'TError> =
| Ok of 'TOk
| Error of 'TError
type ResultA = Result<string, int>
let a = Ok "A"
let o = box a
match o with
| :? ResultA -> printfn "match ResultA"
// | :? ResultA.Ok -> printfn "match" // doesn't compile
| _ when o.GetType().DeclaringType = typedefof<ResultA> -> printfn "match via reflection"
| _ -> printfn "no match"
Run Code Online (Sandbox Code Playgroud)
此示例的输出是“通过反射匹配”,ResultA 永远不会匹配,因为装箱值属于不同的 CLR 类型 - Result.Ok。由于 F# 可区分联合案例表示为其自己的类型,因此装箱值与 ResultA 类型不匹配。此外,不可能将其与 ResultA.OK 匹配,因为在 F# 代码中它不是合法类型。唯一的选择似乎是使用反射手动实例化值,这是低效且愚蠢的,因为该值已经实例化,它就在这里,只是一旦装箱就无法在 F# 代码中访问它。
我是否忽略了什么?是否有更直接的方法来拆箱 F# 可区分联合值?
你只是匹配了不同的类型。您的变量a
不是类型,而是泛型类型,装箱时会被强制转换为泛型类型。ResultA
Result<string, 'a>
Result<string, obj>
要么显式地使变量具有正确的类型:
let a : ResultA = Ok "A"
Run Code Online (Sandbox Code Playgroud)
或者匹配正确的类型:
match o with
| :? Result<string, obj> -> printfn "match ResultA"
Run Code Online (Sandbox Code Playgroud)
两种选择都有效。
关于您的假设的注释:
ResultA 永远不会匹配,因为装箱值属于不同的 CLR 类型 - Result.Ok
原因不是这个。is
类型匹配的工作方式与 C# 中的/运算符相同as
- 即它匹配子类型以及确切类型。DU 成员被编译为 DU 类型本身的子类型。这就是 F# 如何让 .NET 将不同的情况作为一种类型来处理。
关于运行时类型的一般注意事项:
不需要在运行时处理类型。如果可能的话,尽量避免它。经验法则应该是,如果您发现自己在运行时处理类型,则您可能建模了错误的东西。
如果您不确切知道一切是如何运作的,则尤其如此。
归档时间: |
|
查看次数: |
626 次 |
最近记录: |