Table of Contents

Class NullableUnwrap

Namespace
ICSharpCode.Decompiler.IL
Assembly
ICSharpCode.Decompiler.dll

For a nullable input, gets the underlying value.

There are three possible input types:

  • reference type: if input!=null, evaluates to the input
  • nullable value type: if input.Has_Value, evaluates to input.GetValueOrDefault()
  • generic type: behavior depends on the type at runtime. If non-nullable value type, unconditionally evaluates to the input.

If the input is null, control-flow is tranferred to the nearest surrounding nullable.rewrap instruction.

public sealed class NullableUnwrap : UnaryInstruction
Inheritance
NullableUnwrap
Inherited Members

Constructors

NullableUnwrap(StackType, ILInstruction, bool)

public NullableUnwrap(StackType unwrappedType, ILInstruction argument, bool refInput = false)

Parameters

unwrappedType StackType
argument ILInstruction
refInput bool

Fields

RefInput

Whether the argument is dereferenced before checking for a null input. If true, the argument must be a managed reference to a valid input type.

public readonly bool RefInput

Field Value

bool

Remarks

This mode exists because the C# compiler sometimes avoids copying the whole Nullable{T} struct before the null-check. The underlying struct T is still copied by the GetValueOrDefault() call, but only in the non-null case.

Properties

DirectFlags

Gets the flags for this instruction only, without considering the child instructions.

public override InstructionFlags DirectFlags { get; }

Property Value

InstructionFlags

RefOutput

Consider the following code generated for

t?.Method()
on a generic t:
if (comp(box ``0(ldloc t) != ldnull)) newobj Nullable..ctor(constrained[``0].callvirt Method(ldloca t)) else default.value Nullable

Here, the method is called on the original reference, and any mutations performed by the method will be visible in the original variable.

To represent this, we use a nullable.unwrap with ResultType==Ref: instead of returning the input value, the input reference is returned in the non-null case. Note that in case the generic type ends up being Nullable{T}, this means methods will end up being called on the nullable type, not on the underlying type. However, this ends up making no difference, because the only methods that can be called that way are those on System.Object. All the virtual methods are overridden in Nullable{T} and end up forwarding to T; and the non-virtual methods cause boxing which strips the Nullable{T} wrapper.

RefOutput can only be used if RefInput is also used.

public bool RefOutput { get; }

Property Value

bool

ResultType

Gets the stack type of the value produced by this instruction.

public override StackType ResultType { get; }

Property Value

StackType

Methods

AcceptVisitor(ILVisitor)

Calls the Visit*-method on the visitor corresponding to the concrete type of this instruction.

public override void AcceptVisitor(ILVisitor visitor)

Parameters

visitor ILVisitor

AcceptVisitor<T>(ILVisitor<T>)

Calls the Visit*-method on the visitor corresponding to the concrete type of this instruction.

public override T AcceptVisitor<T>(ILVisitor<T> visitor)

Parameters

visitor ILVisitor<T>

Returns

T

Type Parameters

T

AcceptVisitor<C, T>(ILVisitor<C, T>, C)

Calls the Visit*-method on the visitor corresponding to the concrete type of this instruction.

public override T AcceptVisitor<C, T>(ILVisitor<C, T> visitor, C context)

Parameters

visitor ILVisitor<C, T>
context C

Returns

T

Type Parameters

C
T

ComputeFlags()

protected override InstructionFlags ComputeFlags()

Returns

InstructionFlags

PerformMatch(ILInstruction?, ref Match)

protected override bool PerformMatch(ILInstruction? other, ref Match match)

Parameters

other ILInstruction
match Match

Returns

bool

WriteTo(ITextOutput, ILAstWritingOptions)

Writes the ILAst to the text output.

public override void WriteTo(ITextOutput output, ILAstWritingOptions options)

Parameters

output ITextOutput
options ILAstWritingOptions