Por que nenhum é representado como nulo?
CompilationRepresentationFlags.UseNullAsTrueValue
pode ser usado para
Permitir o uso de null como uma representação para discriminadores nulos em uma união discriminada
Option.None
é o exemplo mais proeminente disso.
Por que isso é útil? Como é uma verificação nula melhor do que o mecanismo tradicional para verificar casos de união (o geradoTag
propriedade)?
Isso leva a um comportamento talvez inesperado:
Some(1).ToString() //"Some(1)"
None.ToString() //NullReferenceException
EDITAREu testei a afirmação de Jack de que comparar com null em vez de um campo readonly estático é mais rápido.
[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type T<'T> =
| Z
| X of 'T
let t = Z
Usando ILSpy, eu posso vert
compila para null (como esperado):
public static Test.T<a> t<a>()
{
return null;
}
O teste:
let mutable i = 0
for _ in 1 .. 10000000 do
match t with
| Z -> i <- i + 1
| _ -> ()
Os resultados:
Real: 00: 00: 00.036, CPU: 00: 00: 00.046, GC gen0: 0, gen1: 0, gen2: 0
Se oCompilationRepresentation
o atributo é removidot
torna-se um campo de somente leitura estática:
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();
E os resultados são os mesmos:
Real: 00: 00: 00.036, CPU: 00: 00: 00.031, GC gen0: 0, gen1: 0, gen2: 0
A correspondência de padrões é compilada comot == null
no primeiro caso et is Z
no ultimo.