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
StackTypeargument
ILInstructionrefInput
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
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
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
ResultType
Gets the stack type of the value produced by this instruction.
public override StackType ResultType { get; }
Property Value
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
PerformMatch(ILInstruction?, ref Match)
protected override bool PerformMatch(ILInstruction? other, ref Match match)
Parameters
other
ILInstructionmatch
Match
Returns
WriteTo(ITextOutput, ILAstWritingOptions)
Writes the ILAst to the text output.
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
Parameters
output
ITextOutputoptions
ILAstWritingOptions