Dlaczego brak jest reprezentowany jako null?

CompilationRepresentationFlags.UseNullAsTrueValue może być użyte do

Zezwól na użycie wartości null jako reprezentacji dyskryminatorów zerowych w dyskryminowanym związku

Option.None jest najbardziej widocznym tego przykładem.

Dlaczego jest to przydatne? W jaki sposób sprawdzanie wartości zerowej jest lepsze niż tradycyjny mechanizm sprawdzania przypadków unii (generowanyTag własność)?

Prowadzi to do nieoczekiwanego zachowania:

Some(1).ToString() //"Some(1)"
None.ToString()    //NullReferenceException
EDYTOWAĆ

Przetestowałem twierdzenie Jacka, że ​​porównywanie do pustego zamiast statycznego pola tylko do odczytu jest szybsze.

[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type T<'T> =
  | Z
  | X of 'T

let t = Z

Korzystając z ILSpy, widzęt kompiluje do wartości null (zgodnie z oczekiwaniami):

public static Test.T<a> t<a>()
{
    return null;
}

Test:

let mutable i = 0
for _ in 1 .. 10000000 do
  match t with
  | Z -> i <- i + 1
  | _ -> ()

Wyniki:

Real: 00: 00: 00.036, CPU: 00: 00: 00.046, GC gen0: 0, gen1: 0, gen2: 0

JeśliCompilationRepresentation atrybut został usunięty,t staje się statycznym polem tylko do odczytu:

public static Test.T<a> t<a>()
{
    return Test.T<a>.Z;
}

public static Test.T<T> Z
{
    [CompilationMapping(SourceConstructFlags.UnionCase, 0)]
    get
    {
        return Test.T<T>._unique_Z;
    }
}

internal static readonly Test.T<T> _unique_Z = new Test.T<T>._Z();

A wyniki są takie same:

Real: 00: 00: 00.036, CPU: 00: 00: 00.031, GC gen0: 0, gen1: 0, gen2: 0

Dopasowanie wzorca jest kompilowane jakot == null w pierwszym przypadku it is Z w tym drugim.

questionAnswers(2)

yourAnswerToTheQuestion