Martin Thompson
Martin Thompson

Reputation: 3755

How to represent an F# Type in C# with Empty parameters

I'm trying to avoid creating a default object in F#, at least in its full capacity to that I can represent it in WPF.

I read THIS post . So I tried implenting the type as a class, thinking that it would be optional in C# as well.

type OrderException(?id: Guid, ?orderId: Guid, ?orderNumber: string) = 
    member x.id = id
    member x.OrderID = orderId
    member x.OrderNumber = orderNumber

So - in F# I can create an empty object:

let orderException = new OrderException()

But if I use the library in C# and try to instantiate the object - then I get:

There is no argument given that corresponds to the required formal parameter 'id' of 'Artoo.OrderException.OrderException(FSharpOption, FSharpOption, FSharpOption)' Zimpla.Windows D:\Core\Zimpla\Zimpla.Windows\ViewModels\ResolveExceptionsViewModel.cs 26 N/A

So - back to square one. The only way I can see around this is to have an F# method that creates a "default" version of the object with nothing in it.

Upvotes: 1

Views: 261

Answers (2)

Tomas Petricek
Tomas Petricek

Reputation: 243096

Depending on what exactly you want, it may also be worth using idiomatic F# style, like optional parameters in the ?id format, but adding an overloaded default constructor. If you only need this for C# (or even WPF) then you could even annotate this with an attribute to produce a warning if the constructor is used from F#:

open System

type OrderException(?id: Guid, ?orderId: Guid, ?orderNumber: string) = 
    [<CompilerMessage("Default constructor should not be used from F#!",0)>]
    new() = OrderException(?id=None)
    member x.id = id
    member x.OrderID = orderId
    member x.OrderNumber = orderNumber

OrderException() // F# warning - should not be used!
OrderException(Guid.NewGuid()) // This is fine

Upvotes: 1

Asik
Asik

Reputation: 22123

From F# documentation:

For the purposes of C# and Visual Basic interop you can use the attributes [<Optional; DefaultParameterValue<(...)>] in F#, so that callers will see an argument as optional. This is equivalent to defining the argument as optional in C# as in MyMethod(int i = 3).

type OrderException(
    [<Optional; DefaultParameterValue(Guid())>]id: Guid,
    [<Optional; DefaultParameterValue(Guid())>]orderId: Guid, 
    [<Optional; DefaultParameterValue("")>]orderNumber: string) = 
    member x.id = id
    member x.OrderID = orderId
    member x.OrderNumber = orderNumber

That said, a record with an Empty property is quite an idiomatic pattern and I'd favor this here.

type OrderException = 
  { Id: Guid
    OrderId: Guid
    OrderNumber: String }
with 
    static member Empty = 
      { Id = Guid.Empty
        OrderId = Guid.Empty
        OrderNumber = "" }

Upvotes: 2

Related Questions