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