简体   繁体   中英

Implement interface from C# in F# and add method to update object property(return new instance)

I have the following interface defined in a C# library

public interface IMatch
{
    string CompetitionId { get; }
    int MatchNumber { get; }
    MatchType Type { get; }
    SeriesType SeriesType { get; }
    bool Finished { get; }
}

I've then created a type in my F# library that implements the interface like this

type Match(
            competitionId: string,
            finished: bool,
            matchNumber: int,
            seriesType: SeriesType,
            matchType: MatchType) = 
interface IMatch with
    member this.Finished with get() = finished
    member this.MatchNumber with get() = matchNumber
    member this.SeriesType with get() = seriesType
    member this.Type with get() = matchType
    member this.CompetitionId with get() = competitionId

Now, I read this article and I saw the WithUpdatedEmail method on the Person type:

type Person = {
    FirstName: string
    LastName: string
    Email: string
}

with member this.WithUpdatedEmail email = { this with Email = email }

When calling that method, it will return a new Person instance with the updated email. Is it possible to add a method like that on my Match type? I've tried the following but I can't get it to compile( The record label Finished is not defined ), Im completely new to F# so please bear with me if this isn't possible... :)

type Match(
            competitionId: string,
            finished: bool,
            matchNumber: int,
            seriesType: SeriesType,
            matchType: MatchType) = 
interface IMatch with
    member this.Finished with get() = finished
    member this.MatchNumber with get() = matchNumber
    member this.SeriesType with get() = seriesType
    member this.Type with get() = matchType
    member this.CompetitionId with get() = competitionId

with member this.Finished finished = { this with Finished = finished}

Copy and update record expressions — the one, which allows you to write { rec with prop = val } — is a convenient shortcut for creation of new record with a few changes from existing record instance.

I may be wrong, for sure, but this syntax is allowed for record types only, while you've declared a Match class with custom constructor, which is not a record.

So you may want to use a record instead.

type Match =
    { CompetitionId: string
      Finished: bool
      MatchNumber: int
      SeriesType: SeriesType
      MatchType: MatchType } 
    interface IMatch with
        member this.Finished with get() = this.Finished
        member this.MatchNumber with get() = this.MatchNumber
        member this.SeriesType with get() = this.SeriesType
        member this.Type with get() = this.MatchType
        member this.CompetitionId with get() = this.CompetitionId

    member this.WithFinished finished = { this with Finished = finished}

Member WithFinished is quite useless from F# point of view as you could always use with expression directly.

let m = { CompetitionID = "1"; Finished = false; ...}
let m2 = { m with CompetitionId = "42" }

But it may be suitable for C# interoperability.

If you want to leave Match as a class, then you should implement WithFinished manually providing all the arguments.

member this.WithFinished finished = 
    Match(competitionId, finished, matchNumber, seriesType, matchType)

But I doubt that it will be useful, because interfaces are always implemented as explicit in F#, it means you won't be able to access your Match class properties without a cast to IMatch from F# side.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM