Overriding Constructors in F#

2020-02-11 07:04发布

How would I write the following C# code in F#?

namespace Shared {
    public class SharedRegistry : PageRegistry {
        public SharedRegistry(bool useCache = true)
            : base(useCache) {
            // Repositories
            ForRequestedType<IAddressRepository>().TheDefaultIsConcreteType<SqlAddressRepository>();
            ForRequestedType<ISharedEnquiryRepository>().TheDefaultIsConcreteType<SharedEnquiryRepository>();

            // Services
            ForRequestedType<IAddressService>().TheDefaultIsConcreteType<AddressService>();
            ForRequestedType<ISharedEnquiryService>().TheDefaultIsConcreteType<SharedEnquiryService>();
        }
    }
}

As is as far as I have managed, but I can't work out to inherit from PageRegistry at the same time as declaring my own default constructor.

type SharedRegistry(useCache: bool) =
    inherit PageRegistry(useCache)
    new() = new SharedRegistry(true)

Rich

2条回答
一纸荒年 Trace。
2楼-- · 2020-02-11 07:14

I'm not sure that I understand your question; what you've written above looks like it ought to work fine. If you're asking where to put the rest of the constructor logic, try this:

type SharedRegistry(useCache) as this =
  inherit PageRegistry(useCache)
  do
    this.ForRequestedType<IAddressRepository>().TheDefaultIsConcreteType<SqlAddressRepository>()
    // etc.
  new() = SharedRegistry(true)

If you want to define each constructor individually, you can do that too:

type SharedRegistry =
  inherit PageRegistry
  new(useCache) as this = 
    { inherit PageRegistry(useCache) } then
    this.ForRequestedType<IAddressRepository>().TheDefaultIsConcreteType<SqlAddressRepository>()
    // etc.
  new() = SharedRegistry(true)

Or, you could use an optional argument to your main constructor:

type SharedRegistry(?useCache) as this =
  inherit PageRegistry(defaultArg useCache true)
  do
    this.ForRequestedType<IAddressRepository>().TheDefaultIsConcreteType<SqlAddressRepository>()
    // etc.
查看更多
放我归山
3楼-- · 2020-02-11 07:18

Your C# class uses parameters with default value which is slightly different than overloaded constructors. In any case, F# supports both overloaded constructors and default parameters.

Using default values of a parameters, the code would look like this:

type SharedRegistry(?useCache: bool) = 
    do 
      // constructor logic
    inherit PageRegistry(defaultArg useCache true) 

Now you can create an instance as follows:

let r1 = new SharedRegistry() // using the default value
let r2 = new SharedRegistry(false) // specified explicitly
let r3 = new SharedRegistry(useCache=false) // using named parameter

I belive that using named parameters is slightly more elegant in F#. The way it works is that the parameter useCache becomes an option<bool> under the cover (This may be a problem if you wanted to use the class from C#)

Regarding overloaded constructors - Your F# code should be correct (see the answer from kvb). In general, it is probably better to have at least one implicit constructor (as that allows you to access constructor parameters inside the body of the class automatically, declare fields using let and implement constructor logic using do). The implicit constructor should be the one that takes all the parameters. In some cases, you may want to make it private, which can be done like this:

type SharedRegistry private (useCache: bool) = 
    inherit PageRegistry(useCache) 
    do 
      // constructor logic
    new () = SharedRegistry(true)
查看更多
登录 后发表回答