生成的类型提供程序:高级示例
Generated Type Provider: Advanced sample
是否可以编写生成的类型提供程序来提供与以下 F# 代码等效的类型?
[<ProvidedTypeFlag("myTypeA")>]
type A(x:int) =
inherit ValueType(x)
member __.X = x+1
[<ProvidedTypeFlag("myTypeB")>]
type B(value:ValueType) =
member __.Raw = value
member __.toA = A(value.X)
interface IComparable with
member this.CompareTo obj =
match obj with
| :? B as other -> this.Raw.X.CompareTo (other.Raw.X)
| _ -> invalidArg "obj" "not a B"
[<ProvidedTypeFlag("myTypeC")>]
type C() =
static member Process(a:A) =
seq {
for x in [1..a.X] do
yield B(ValueType(x))
} |> Set.ofSeq
假设我在同一个程序集中有以下类型
// Value type that hold some data from 3rd party system
type ValueType (x:int) =
member __.X = x
// Custom attribute that I want to have on provided types
[<AttributeUsage(AttributeTargets.Class, AllowMultiple=false)>]
type ProvidedTypeFlagAttribute(originName:string) =
inherit System.Attribute()
member __.OriginName = originName
如果可能,请提供一个示例,说明如何使用 ProvidedTypes.fs
看这个好像需要几个小块。
添加自定义属性
我用的是这样的小帮手:
type CustomAttributeDataExt =
static member Make(ctorInfo, ?args, ?namedArgs) =
{ new CustomAttributeData() with
member __.Constructor = ctorInfo
member __.ConstructorArguments = defaultArg args [||] :> IList<_>
member __.NamedArguments = defaultArg namedArgs [||] :> IList<_> }
可选的 args 和 namedArgs 使 like 更容易一些,代码也更清晰。当我想添加自定义属性时,如果有多个,我通常会添加几个类型化的帮助程序,以使代码更清晰:
module Attributes =
let MakeActionAttributeData(argument:string) =
CustomAttributeDataExt.Make(typeof<ActionAttribute>.GetConstructor(typeof<string>),
[| CustomAttributeTypedArgument(typeof<ActionAttribute>, argument) |])
open Attributes
myProperty.AddCustomAttribute <| Attributes.MakeActionAttributeData("attributeData")
添加调用基类型的构造函数
再说一遍,我有一些反思的小帮手:
type Type with
member x.GetConstructor(typ) =
x.GetConstructor([|typ|])
member x.TryGetConstructor(typ:Type) =
x.GetConstructor(typ) |> function null -> None | v -> Some v
...
照常创建您的 providedType(记得设置 IsErased=false),然后
//string ctor
match providedType.TryGetConstructor(typeof<string>) with
| None -> failwithf "No string constructor found for type: %s" providedType.Name
| Some ctor -> let stringCtor = ProvidedConstructor([ProvidedParameter("theString", typeof<string>)], InvokeCode=Expr.emptyInvoke, BaseConstructorCall = fun args -> ctor, args)
providedController.AddMember(stringCtor)
我认为应该在别处记录其他部分,尤其是添加普通成员等。
是否可以编写生成的类型提供程序来提供与以下 F# 代码等效的类型?
[<ProvidedTypeFlag("myTypeA")>]
type A(x:int) =
inherit ValueType(x)
member __.X = x+1
[<ProvidedTypeFlag("myTypeB")>]
type B(value:ValueType) =
member __.Raw = value
member __.toA = A(value.X)
interface IComparable with
member this.CompareTo obj =
match obj with
| :? B as other -> this.Raw.X.CompareTo (other.Raw.X)
| _ -> invalidArg "obj" "not a B"
[<ProvidedTypeFlag("myTypeC")>]
type C() =
static member Process(a:A) =
seq {
for x in [1..a.X] do
yield B(ValueType(x))
} |> Set.ofSeq
假设我在同一个程序集中有以下类型
// Value type that hold some data from 3rd party system
type ValueType (x:int) =
member __.X = x
// Custom attribute that I want to have on provided types
[<AttributeUsage(AttributeTargets.Class, AllowMultiple=false)>]
type ProvidedTypeFlagAttribute(originName:string) =
inherit System.Attribute()
member __.OriginName = originName
如果可能,请提供一个示例,说明如何使用 ProvidedTypes.fs
看这个好像需要几个小块。
添加自定义属性
我用的是这样的小帮手:
type CustomAttributeDataExt =
static member Make(ctorInfo, ?args, ?namedArgs) =
{ new CustomAttributeData() with
member __.Constructor = ctorInfo
member __.ConstructorArguments = defaultArg args [||] :> IList<_>
member __.NamedArguments = defaultArg namedArgs [||] :> IList<_> }
可选的 args 和 namedArgs 使 like 更容易一些,代码也更清晰。当我想添加自定义属性时,如果有多个,我通常会添加几个类型化的帮助程序,以使代码更清晰:
module Attributes =
let MakeActionAttributeData(argument:string) =
CustomAttributeDataExt.Make(typeof<ActionAttribute>.GetConstructor(typeof<string>),
[| CustomAttributeTypedArgument(typeof<ActionAttribute>, argument) |])
open Attributes
myProperty.AddCustomAttribute <| Attributes.MakeActionAttributeData("attributeData")
添加调用基类型的构造函数
再说一遍,我有一些反思的小帮手:
type Type with
member x.GetConstructor(typ) =
x.GetConstructor([|typ|])
member x.TryGetConstructor(typ:Type) =
x.GetConstructor(typ) |> function null -> None | v -> Some v
...
照常创建您的 providedType(记得设置 IsErased=false),然后
//string ctor
match providedType.TryGetConstructor(typeof<string>) with
| None -> failwithf "No string constructor found for type: %s" providedType.Name
| Some ctor -> let stringCtor = ProvidedConstructor([ProvidedParameter("theString", typeof<string>)], InvokeCode=Expr.emptyInvoke, BaseConstructorCall = fun args -> ctor, args)
providedController.AddMember(stringCtor)
我认为应该在别处记录其他部分,尤其是添加普通成员等。