如何使用方法在F#中的默认构造函数中设置属性

Ale*_*erM 3 f#

我正在尝试编写一个构造函数,该构造函数假定调用类中定义的方法并将结果分配给成员。在C#中,它将类似于:

public class Test
{
    public int Value { get; private set;}

    private static int SomeLogic(int a, int b)
    {
        return a + b;
    }

    public Test(int a, int b)
    {
        this.Value = SomeLogic(a,b);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我不知道该怎么做F#。

Jus*_*mer 5

在F#中实现此目标的两种不同方式的示例:

type Test_UsesVal =
  val value : int
  new (a, b) = { value = someLogic a b }
  member x.Value = x.value

type Test_Preferred (a : int, b: int) =
  let value = someLogic a b
  member x.Value = value
Run Code Online (Sandbox Code Playgroud)

有两个缺点的例子:

// This type is default constructible and when using default ctor someLogic is not used
type Test_DefaultConstructible () =
  let mutable value = 0
  new (a, b) as x = Test_DefaultConstructible () then x.Value <- someLogic a b
  member x.Value with get () = value and private set v = value <- v

// This type has 2 constructors and using single value ctor someLogic is not used
type Test_2Constructors (value : int) =
  new (a, b) = Test_2Constructors (someLogic a b)
  member x.Value with get () = value
Run Code Online (Sandbox Code Playgroud)

提到自引用类型时,我只想指出,使类型成为自引用类型会增加隐藏的开销:

// Self referential types add hidden overhead
type Test_SelfReferential (a : int, b: int) as this =
  let computeValue () = someLogic this.A this.B

  member x.A      = a
  member x.B      = b
  member x.Value  = computeValue ()
Run Code Online (Sandbox Code Playgroud)

反编译开销显示:

[CompilationMapping(SourceConstructFlags.ObjectType)]
[Serializable]
public class Test_SelfReferential
{
  internal int b;

  internal int a;

  // An extra field added
  internal FSharpRef<Program.Test_SelfReferential> @this = new FSharpRef<Program.Test_SelfReferential>(null);

  // An extra field added
  internal int init@29-1;

  public int A
  {
    get
    {
      // An extra check added in each method 
      if (this.init@29-1 < 1)
      {
        LanguagePrimitives.IntrinsicFunctions.FailInit();
      }
      return this.a;
    }
  }

  public int B
  {
    get
    {
      // An extra check added in each method 
      if (this.init@29-1 < 1)
      {
        LanguagePrimitives.IntrinsicFunctions.FailInit();
      }
      return this.b;
    }
  }

  public int Value
  {
    get
    {
      // An extra check added in each method 
      if (this.init@29-1 < 1)
      {
        LanguagePrimitives.IntrinsicFunctions.FailInit();
      }
      return this.computeValue();
    }
  }

  public Test_SelfReferential(int a, int b) : this()
  {
    this.a = a;
    this.b = b;
    // An extra init added in .ctor
    this.@this.contents = this;
    this.init@29-1 = 1;
  }

  [CompilerGenerated]
  internal int computeValue()
  {
    // Extra checks added
    return LanguagePrimitives.IntrinsicFunctions.CheckThis<Program.Test_SelfReferential>(this.@this.contents).A + LanguagePrimitives.IntrinsicFunctions.CheckThis<Program.Test_SelfReferential>(this.@this.contents).B;
  }
}
Run Code Online (Sandbox Code Playgroud)

F#中自引用类型的隐藏开销曾经使我性能下降(在某些用例中性能下降了50%)。

  • 关于这种看似无害的语法更改所导致的开销的非常有趣的评论,毕竟我做了这么长时间的 F#... (2认同)