实现接口的非泛型方法中泛型的模式匹配
我有一个令人沮丧的问题。我正在 ASP.NET MVC 中构建 视图引擎 并实现接口 IViewEngine。在其中一种方法中,我试图动态地找出视图结果的类型。有时结果是一个模板(类型为 Template<'key>)。这些键用于定位模板中的占位符,其想法是使用可区分的联合,对于每个网站来说可能是唯一的。它可能看起来像这样:
type MasterKey = | HeadContent | HeaderContent | MainContent | FooterContent
let MasterTemplate : Template<MasterKeys> = ...
现在,问题是这样的:由于我正在实现一个接口,所以我无法控制方法签名。由于我无法添加泛型类型参数,因此 'a 将转换为 obj,并且模板将不匹配以下内容:
match result with
| :? foo -> ...
| :? bar -> ...
| :? Template<'a> -> ...
有什么想法吗?
I have a frustrating problem. I'm building a view engine in ASP.NET MVC and are implementing the interface IViewEngine. In one of the methods I'm trying to dynamically figure out the type of the result of a view. Sometimes the result is a template (with the type Template<'key>). The keys are used to target a placeholder in the template, and the idea is to use a discriminated union, potentially unique for each web site. It could look like this:
type MasterKey = | HeadContent | HeaderContent | MainContent | FooterContent
let MasterTemplate : Template<MasterKeys> = ...
Now, the problem is this: since I'm implementing an interface, I have no control over the method signature. Since I can not add a generic type parameter, the 'a will be converted to an obj and the Template will not be a match below:
match result with
| :? foo -> ...
| :? bar -> ...
| :? Template<'a> -> ...
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不幸的是,没有办法很好地做到这一点。如果您可以控制
Template<'T>
类型,那么最好的选择是创建一个非泛型接口(例如ITemplate
)并在中实现它>模板<'T>
类型。然后你可以检查接口:如果不是这种情况,那么你唯一的选择就是使用一些反射魔法。您可以实现一个活动模式,当类型为某个
Template<'T>
值时进行匹配,并返回用作泛型的类型列表(System.Type
对象)论据。在伪代码中,您希望将其作为泛型类型参数'a
获取 - 不可能将其作为编译时类型参数获取,但您可以将其作为运行时类型信息获取:现在您可以编写以下模式匹配代码:
最后一个问题是 - 如何使用此运行时类型信息来运行一些通用代码。我能想到的最佳选择是使用反射调用泛型方法(或函数) - 然后您可以将运行时类型信息指定为泛型参数,因此代码可以是泛型的。最简单的选项是调用类型的静态成员:
关键思想是将模式匹配的主体(不能具有泛型类型参数)移动到方法(可以具有泛型类型参数)中,并使用反射动态运行该方法。
您也可以更改代码以使用
let
函数而不是static member
- 使用反射查找函数只是稍微困难一些。Unfortunately, there is no way to do this nicely. If you have control over the
Template<'T>
type, then the best option is to create a non-generic interface (e.g.ITemplate
) and implement that in theTemplate<'T>
type. Then you can just check for the interface:If that's not the case, then your only option is to use some reflection magic. You can implement an active pattern that matches when the type is some
Template<'T>
value and returns a list of types (System.Type
objects) that were used as generic arguments. In your pseudo-code, you wanted to get this as the generic type parameter'a
- it isn't possible to get that as compile-time type parameter, but you can get that as runtime type information:Now you can write the following pattern matching code:
The last problem is - how can you use this runtime type information to run some generic code. The best option I can think of is to invoke a generic method (or a function) using reflection - then you can specify the runtime type information as a generic parameter and so the code can be generic. The simplest option is to invoke static member of a type:
The key idea is that you move body of a pattern matching (which cannot have generic type parameters) into a method (that can have generic type parameters) and run the method dynamically using reflection.
You could change the code to use
let
function instead ofstatic member
as well - it is only slightly more difficult to find the function using reflection.您能否根据它使用的
'key
类型使整个视图引擎类通用?个别项目将需要继承您的视图引擎类并在流程中指定键的类型。Can you make the whole view engine class generic, according to the type of
'key
it uses? Indivudual projects will need to inherit from your view engine class and specify the type of key in the process.