F#`该表达式应具有类型'IDictionary <Type,obj>',但此处具有类型'Dictionary <Type,obj>'

时间:2019-06-07 12:11:50

标签: f#

我正在尝试将C# class转换为F#:

type Aggregator<'T when 'T : (new : unit -> 'T)>()=
    static let ApplyMethod = "Apply"
    member val private _aggregations : IDictionary<Type, obj> = new Dictionary<Type, obj>()
    member val AggregateType = typeof<'T> with get
    member val Alias = Unchecked.defaultof<string> with get

但是,即使这个简单的代码似乎也无法编译:

  

Program.fs:1189该表达式应具有类型       'IDictionary<Type,obj>'
  但是这里有类型       'Dictionary<Type,obj>'

这是否意味着使用接口IDictionary<Type, obj>类型声明的字段无法推断出传递的值,而该值知道该特定值实现了该接口Dictionary<Type, obj>

实际上,如果我明确地向IDictionary<Type, obj>转换:

member val private _aggregations : IDictionary<Type, obj> =
    (new Dictionary<Type, obj>() :> IDictionary<Type, obj>)

这行得通,这是否意味着F#在这方面比C#更严格?

1 个答案:

答案 0 :(得分:1)

正如评论中指出的那样,F#确实需要明确的内容:

type Aggregator<'T when 'T : (new : unit -> 'T)>()=
    static let ApplyMethod = "Apply"
    member val private _aggregations : IDictionary<Type, obj> = new Dictionary<Type, obj>() :> IDictionary<Type, obj>)
    member val AggregateType = typeof<'T> with get
    member val Alias = Unchecked.defaultof<string> with get

旁注:

  • 顺便说一句,并不是在F#中可以使用C#进行的所有操作(例如,没有protected访问修饰符)。

  • 转换结果:

type Aggregator<'T when 'T : (new : unit -> 'T) and 'T : not struct> (overrideMethodLookup : IEnumerable<MethodInfo>)=
    let aggregations : IDictionary<Type, obj> = (new Dictionary<Type, obj>() :> IDictionary<Type, obj>) 
    let aggregateType = typeof<'T>
    let mutable alias = Unchecked.defaultof<string>
    do
        alias <-  typeof<'T>.Name.ToTableAlias();
        overrideMethodLookup.Each(fun (method : MethodInfo) ->
            let mutable step = Unchecked.defaultof<obj>
            let mutable eventType = method.GetParameters().Single<ParameterInfo>().ParameterType;
            if eventType.Closes(typedefof<Event<_>>) then
                eventType <- eventType.GetGenericArguments().Single();
                step <- typedefof<EventAggregationStep<_,_>>.CloseAndBuildAs<obj>(method, [| typeof<'T>; eventType |]);
            else
                step <- typedefof<AggregationStep<_,_>>.CloseAndBuildAs<obj>(method, [| typeof<'T>; eventType |]);
            aggregations.Add(eventType, step)
        ) |> ignore

    static let ApplyMethod = "Apply"

    new() = new Aggregator<'T>(typeof<'T>.GetMethods()
                               |> Seq.where (fun x -> x.Name = ApplyMethod &&
                                                      x.GetParameters().Length = 1))

    member this.Add<'TEvent>(aggregation: IAggregation<'T, 'TEvent>) =
        if aggregations.ContainsKey(typeof<'TEvent>) then
            aggregations.[typeof<'TEvent>] <- aggregation
        else
            aggregations.Add(typeof<'TEvent>, aggregation)
        this

    member this.Add<'TEvent>(application: Action<'T, 'TEvent>) =
        this.Add(new AggregationStep<'T, 'TEvent>(application));

    interface IAggregator<'T> with

        member this.AggregatorFor<'TEvent>() =
            if aggregations.ContainsKey(typeof<'TEvent>) then
                aggregations.[typeof<'TEvent>].As<IAggregation<'T, 'TEvent>>()
            else
                null

        member this.Build(events, session, state) =
            events.Each(fun (x : IEvent) -> x.Apply(state, this)) |> ignore
            state

        member this.Build(events, session) =
            (this :> IAggregator<'T>).Build(events, session, new 'T());

        member this.EventTypes =
            aggregations.Keys.ToArray();

        member this.AggregateType =
            aggregateType

        member this.Alias =
            alias

        member this.AppliesTo(stream) =
            stream.Events.Any(fun x -> aggregations.ContainsKey(x.Data.GetType()));