为什么F#编译器会检查新创建的数组是否为空?

时间:2015-11-18 10:22:13

标签: f#

我正在玩F#,并希望检查它与C#相比如何生成代码并找到一条奇怪的行。 我使用dotTrace来反编译代码并使C#等效。我还尝试使用LinqPad检查IL代码。

我的代码非常小。

open System

[<EntryPoint>]
let main argv =
    let mutable sum = 0
    // 1000 or 997
    //let arr : int array = Array.zeroCreate 997
    //let arr  = Enumerable.Range(0, 997).ToArray()
    let arr :int array = [|0..997|]
    arr |> Array.iter (fun x -> sum <- sum + x)
    printfn "%i" sum
    0

这就是我得到的。

  {
    int func = 0;
    int[] numArray = SeqModule.ToArray<int>(Operators.CreateSequence<int>(Operators.OperatorIntrinsics.RangeInt32(0, 1, 997)));
    if ((object) numArray == null)
      throw new ArgumentNullException("array");
    int length = numArray.Length;
    int index = 0;
    int num1 = length - 1;
    if (num1 >= index)
    {
      do
      {
        int num2 = numArray[index];
        func += num2;
        ++index;
      }
      while (index != num1 + 1);
    }
    PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<int, Unit>>(Console.Out, (PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit>) new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("%i")).Invoke(func);
    return 0;
  }
}

这就是IL的样子。

  // IL_0019: stloc.1      // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
  // IL_001a: ldloc.1      // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
  // IL_001b: box          int32[]
  // IL_0020: brfalse.s    IL_0025
  // IL_0022: nop          
  // IL_0023: br.s         IL_0030
  // IL_0025: ldstr        "array"
  // IL_002a: newobj       instance void [mscorlib]System.ArgumentNullException::.ctor(string)
  // IL_002f: throw

使用Release,.Net 4.6,FSharp.Core 4.4.0.0编译,优化代码,生成尾调用。

我对NULL检查和强制转换非常好奇。

(object) numArray == null

我明白为什么完成obj演员。该数组不是null,不能在没有。

的情况下进行检查

我很好奇(不认为这是一个问题)而且问题更多的是关于编译器。

  1. 为什么检查null是否有用?我没有定义选项类型。
  2. 在什么条件下会触发例外。

1 个答案:

答案 0 :(得分:2)

该检查是implementation of Array.iter的一部分。编译器似乎不够聪明,无法确定box arg在这种情况下永远不会是null