f# - 生成的类型提供程序 : Advanced sample

标签 f# type-providers

是否可以编写一个生成的类型提供程序来提供与以下 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使事情变得更容易,而且代码也更干净。当我想添加自定义属性时,如果有多个,我通常会添加多个类型化帮助器以使代码中的内容更清晰:

module Attributes =
let MakeActionAttributeData(argument:string) =
    CustomAttributeDataExt.Make(typeof<ActionAttribute>.GetConstructor(typeof<string>),
                                [| CustomAttributeTypedArgument(typeof<ActionAttribute>, argument) |])

open Attributes
myProperty.AddCustomAttribute <| Attributes.MakeActionAttributeData("attributeData")

添加调用基类型的构造函数

同样,我有一些用于反射(reflection)的小 helper :

    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# - 生成的类型提供程序 : Advanced sample,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27868579/

相关文章:

web-services - 使用 F# WsdlService 类型提供程序编译错误

.net - F# 字符串连接运算符的用途是什么 ^

f# - 为什么 F# 的 Collections.Seq 模块基本上重新实现了所有的 Enumerable 扩展方法?

visual-studio - Visual Studio 找不到 SQLProvider

class - 是否应该包装类型提供程序包含在类中具有副作用的值?

sql-server - 无法使用 F# TypeProvider 读取日期

f# - F# 类型提供程序与传统的 'type providers' 相比有什么优势?

linq - 是否有等效于 Enumerable.DefaultIfEmpty 的 F#?

F# - 重载函数

configuration - 从 F# 脚本使用 app.config