F # `Ожидалось, что это выражение будет иметь тип 'IDictionary <Type, obj>', но здесь есть тип 'Dictionary <Type, obj>' - PullRequest
1 голос
/ 07 июня 2019

Я пытаюсь преобразовать C # класс в 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 Ответ

1 голос
/ 07 июня 2019

Как указано в комментарии, 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

Примечания:

  • Кстати, не все, что вы можете сделать в C #, этовозможно в F # (например, без 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()));   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...