背景
我正在学习生成型提供者.
我在这里和这里使用了Cameron Taggart的VectorTP示例.在该代码中,他为具有设计时指定数量的属性的向量类构建C#代码,编译它并返回生成的类型.它运作良好.
例如,此客户端代码编译并运行:
type Vector2D = Vector<"X", "Y">
let v1 = Vector2D()
v1.X <- 3.14
v1.Y <- 2.91
Run Code Online (Sandbox Code Playgroud)
如果你在设计时查看类型提供者代码内部的内容,你会看到类型提供者代码被调用如下:
ITypeProvider.ApplyStaticArguments(
VectorTP.Vector, // typeWithoutArguments
[|"ConsoleApplication8"; "Vector2D"|], // typeNameWithArguments
[|"X"; "Y"; ""; ""; ""; ""; ""|]) // staticArguments
Run Code Online (Sandbox Code Playgroud)
一切看起来都不错.
问题
此客户端代码无法编译:
type Vector2D = Vector<"X", "Y">
let list = System.Collections.Generic.List<Vector2D>()
Run Code Online (Sandbox Code Playgroud)
这一次,如果您在设计时查看类型提供程序代码内部的内容,则在将其添加到客户端代码时会看到此附加调用List<Vector2D>:
ITypeProvider.ApplyStaticArguments(
Mindscape.Vectorama.Vector2D, // typeWithoutArguments
[|"Vector2D,"|], // typeNameWithArguments
[|""; ""; ""; ""; ""; ""; ""|]) // staticArguments
Run Code Online (Sandbox Code Playgroud)
似乎类型提供程序框架(正确的术语?)正在调用ITypeProvider.ApplyStaticArguments基于Vector2D没有任何静态参数的生成类型.但是,Vector2D已经是生成的类型?!
VectorTP示例未正确处理此情况,因此客户端代码将无法编译.
注意
我确实尝试将type Vector2D = Vector<"X", "Y">声明移动到单独的DLL中,然后引用该DLL.当然,这是按预期工作的.生成的Vector2D类在该点看起来就像任何其他类型.
复杂性似乎是生成类型并将其用作同一程序集中的泛型参数(或脚本,通过我没有尝试过).
问题
这是"类型提供程序框架"中的问题吗?或者这是预期的行为?
ApplyStaticArguments当我使用生成的类型作为泛型类型参数时,为什么被调用?
如果ITypeProvider应该处理这种情况,那么适当的反应是什么?
阅读完评论并做更多实验后,这就是我的结论.
1.这是"类型提供者框架"中的问题吗?或者这是预期的行为?
这不是我预期的行为.
当您尝试将生成的类型用作泛型类型参数时,问题才会变得明显.当您将生成的类型用作泛型类型参数时,框架将调用ITypeProvider.GetStaticParameters该生成的类型.目前还不清楚为什么需要这样做.
无论如何,由于这个意外的调用,执行ITypeProvider.GetStaticParameters()不能像这样简单:
member this.GetStaticParameters(typeWithoutArguments) =
[1..7] |> List.map (fun i -> stringParameter i "") |> List.toArray
Run Code Online (Sandbox Code Playgroud)
必须是这样的:
member this.GetStaticParameters(typeWithoutArguments) =
if typeWithoutArguments = typeof<Vector> then
[1..7] |> List.map (fun i -> stringParameter i "") |> List.toArray
else
[||] // for the generated types like Vector2D
Run Code Online (Sandbox Code Playgroud)
完成上述更改后,我能够编译使用该客户端的客户端代码List<Vector2D>.
2.当我使用生成的类型作为泛型类型参数时,为什么要调用ApplyStaticArguments?
请注意,我原来问题的重点是为什么ITypeProvider.ApplyStaticArguments被调用.ApplyStaticArguments被调用的原因是因为GetStaticParameters说生成的类型(Vector2D)本身需要静态参数.修复后GetStaticParameters,ApplyStaticArguments不再调用生成的类型.现在这是有道理的.
3.如果ITypeProvider应该处理这种情况,那么正确的响应是什么?
已经在上面提到了.然而,它提出了一个更大的问题,"生成型提供者的一个好例子在哪里?" 这个问题已经被问到了,但这里没有回答.
最后,关于ProvideTypes.fs
在评论中,有一个问题是使用该ProvidedTypes.fs库是否可以解决这个问题.我重复这个练习ProvidedTypes.fs并且最初遇到了同样的问题.也就是说,只要我在客户端代码中使用生成的类型作为泛型类型参数,客户端代码就不会编译.即使ProvidedTypes.fs你必须认识到你的ProvidedTypeDefinition.DefineStaticParameters(相当于ITypeProvider.GetStaticParameters)方法的处理程序必须考虑到它可能被称为传递你生成的类型的事实.
| 归档时间: |
|
| 查看次数: |
664 次 |
| 最近记录: |