在F#中内联C#对象创建

问题描述

我正在尝试以某些F#代码与C#库互操作。考虑以下C#,好像它是我正在使用的库一样(或跳过下面以查看我首先使用的实际库):

public class Options
{
    public Options(string name)
    {
        Name = name;
    }

    public string Name { get; }
    public string SomeProperty { get; set; }
}

public class ServiceBuilder
{
    public ServiceBuilder ApplyOptions(Options options)
    {
        //Apply Options in some way
        return this;
    }

    public TheService Build()
    {
        return new TheService();
    }
}

public class TheService
{
}

然后我试图创建服务,但要保持流利,我有以下F#代码

//Valid Approach but not inlined :(
let options = Options("Test")
options.someProperty <- "SomeValue"

let theService = 
    ServiceBuilder()
        .ApplyOptions(options)
        .Build();
//Invalid Approach because SomeProperty is not virtual
let theService2 =
    ServiceBuilder()
        .ApplyOptions({
            new Options("Test2") with
                member _.someProperty = "SomeValue2"
        })
        .Build()

在我尝试创建“ theService2”的F#中,是否可以通过某种方式初始化内联的方式?在C#中,我只使用对象初始化器。 F#对象表达式不可用,因为我无法控制该类使该属性为虚拟。

对于上面我的C#所模拟的其他上下文,我专门尝试使用Serilog.Sinks.ElasticSearch nuget包创建Serilog Logger,并在F#中大致执行以下代码(再次,内联):

var loggerConfig = new LoggerConfiguration()
    .Writeto.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200") ){
         AutoRegisterTemplate = true,AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6
     });

解决方法

在F#中,您也可以assign values to properties at initialization,因此要在单个表达式中创建Options实例,您可以执行以下操作:

Options("Test",SomeProperty="SomeValue")
,

要从C#直接翻译-按照@ rob.earwaker的答案中的建议,可以使用属性初始化器。

但是,还请注意,在F#中,一切都是表达式。没有像C#中那样的“语句”,每段代码都有某种结果。这也适用于“复合”,也就是说,诸如let块之类的代码段。这意味着,即使您不想使用属性初始化程序,也可以内联进行初始化:

let service =
  ServiceBuilder()
    .ApplyOptions(
      let o = Options("Test")
      o.SomeProperty <- "SomeValue"
      o
    )
    .Build()

或者使用let .. in和分号将所有内容放在同一行:

let service =
  ServiceBuilder()
    .WithOptions(let o = Options("Test") in o.SomeProperty <- "SomeValue"; o)
    .Build()

与C#不同,此方法还可以将初始化分解为可重用的片段:

let service =
  ServiceBuilder()
    .WithOptions(let o = Options("bar") in mutateSomeOptions(o); mutateOtherOptions(o); o)
    .Build()