Skip to content

Type conversions

SyntaxDescriptionNote
int b = a;Conversion to the same type
long b = a;Implicit conversion to a wider type
byte b = 200;Conversion of a constant that fits the rangeVariables can’t be assigned the same way.
(int)dExplicit conversion to a narrower typeConverting a float to an integer halts execution on a value outside the range.
int a = c; char d = (char)a;Conversion between char and numeric typesGoing back from int to char requires a cast.
Mode m = 0;Conversion of the constant 0 to an enumOther numeric types require a cast.
(int)mConversion from an enum to a number
(Mode)aConversion from a number to an enum
(B)aConversion between enums
object o = a;Boxing a value type
(int)oUnboxing
o is intChecking the type of the contentsIt can only be checked when the value is an object and the type being tested is numeric, bool, char, or string.
Component c = target;Conversion to a base type
IThing t = v;Conversion to an interface type
(Transform)oConversion from object to a reference type
string s = null;Assigning null
return value;Conversion from a type parameter to objectA conversion from object back to a type argument can’t be written.
int a = default;Writing default
Holder h = new();Creation with the type name omitted
long v = c ? 1 : 2;Matching types on both sides of ?:
long v = k switch { … };Matching types across switch expression cases
a.ToString()Conversion to a stringA number with no format specified takes the default format.
int.Parse("1")Reading from a string
SyntaxDescriptionErrorReasonAlternative
int? a = 1;A type meaning a value or nullTUKI0001, TUKI0101, TUKI0102runtimeUse a separate variable to hold whether a value is present
int b = (int)a;Extract the value from a value-or-null typeTUKI0102, TUKI0001, TUKI0099runtimeSame as above
long? b = a;Convert between value-or-null types (a lifted conversion)TUKI0001, TUKI0101, TUKI0102runtimeSame as above
dynamic d = 1;Determine the type at runtimeTUKI0102, TUKI0099runtimeWrite the type
(long, long) b = a;Convert between tuples element by elementTUKI0099not yetMove the elements one at a time
((int, int))aExplicitly convert a tupleTUKI0099not yetSame as above
(T)valueConvert from object back to a type parameterTUKI0099undecidedRewrite it without using a type parameter
public static implicit operator float(Meters m)Define your own implicit conversionTUKI0001not yetWrite a conversion method and call it
public static explicit operator int(Meters m)Define your own explicit conversionTUKI0001not yetSame as above
System.Action a = Helper;Turn a method name into a delegateTUKI0108runtimePass the method name and call it (SendCustomEvent)
delegate(int x) { … }Write a function inline as a valueTUKI0108, TUKI0001runtimeSame as above
throw new System.Exception()Throw an exception (as an expression or a statement)TUKI0001, TUKI0101runtimeRepresent failure with a return value or state
System.FormattableString s = $"…";Hold an interpolated string as a formatting targetTUKI0102, TUKI0101, TUKI0099runtimeBuild it as a string
System.Span<int> s = a;Borrow a view of a contiguous regionTUKI0102, TUKI0101, TUKI0099runtimeUse the array directly
c as TransformBecome null if the conversion failsTUKI0001not yetIf the type is known, write a cast ((Transform)c). If it’s a union or an interface, receive it with a type pattern.
o is TransformAsk at runtime about a type that may have derived typesTUKI0001by designIf the type is known, write a cast ((Transform)o). If it’s a union or an interface, receive it with a type pattern.
IProducer<IThing> q = p;Convert a generic interface based on the derivation relation of its type parameter (variance)TUKI0001undecidedA generic interface is supported for declaration and implementation only. Rewrite it into a form that doesn’t use it as a value
A type meaning “a value or null”Not available, because the runtime has no such type (TUKI0102). Taking a value type through ?. can’t be written for the same reason: the result would be this type
Conversions determined by the target typedefault, new(), ?:, and switch expressions are all converted to the type on the left
Converting between tuplesNot possible (TUKI0099). Declaring them is
using UnityEngine;
using Tsukimi;
public class CvIdentity : TsukimiBehaviour
{
void Start()
{
int a = 1;
int b = a;
Debug.Log(b); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class ConversionsImplicitNumeric : TsukimiBehaviour
{
void Start()
{
int a = 1;
long b = a;
float c = a;
double d = c;
Debug.Log(b + c + d); // => 3
}
}

Conversion of a constant that fits the range

Section titled “Conversion of a constant that fits the range”

A constant that fits in the range can be assigned to a narrower type without a cast.

using UnityEngine;
using Tsukimi;
public class CvConstantExpr : TsukimiBehaviour
{
void Start()
{
byte b = 200;
short s = 30000;
Debug.Log(b + s); // => 30200
}
}

The result of passing a value outside the range is in Numeric overflow and conversion.

using UnityEngine;
using Tsukimi;
public class ConversionsExplicitNumeric : TsukimiBehaviour
{
void Start()
{
double d = 1.9;
int a = (int)d;
byte b = (byte)a;
Debug.Log(a + b); // => 2
}
}

char converts to int without writing a cast.

using UnityEngine;
using Tsukimi;
public class ConversionsCharAndInt : TsukimiBehaviour
{
void Start()
{
char c = 'a';
int a = c;
char d = (char)(a + 1);
Debug.Log(d); // => b
}
}

The only implicit conversion is from the constant 0.

using UnityEngine;
using Tsukimi;
public enum Mode { Off, On }
public class CvImplicitEnumZero : TsukimiBehaviour
{
void Start()
{
Mode m = 0;
Debug.Log((int)m); // => 0
}
}
using UnityEngine;
using Tsukimi;
public enum Mode { A, B }
public class ConversionsEnumToInt : TsukimiBehaviour
{
void Start()
{
Mode m = Mode.B;
int a = (int)m;
Debug.Log(a); // => 1
}
}
using UnityEngine;
using Tsukimi;
public enum Mode { A, B }
public class ConversionsIntToEnum : TsukimiBehaviour
{
void Start()
{
int a = 1;
Mode m = (Mode)a;
Debug.Log(m == Mode.B); // => true
}
}
using UnityEngine;
using Tsukimi;
public enum A { Zero, One }
public enum B { Zero, One }
public class CvEnumToEnum : TsukimiBehaviour
{
void Start()
{
A a = A.One;
B b = (B)a;
Debug.Log((int)b); // => 1
}
}

Assigning a value type to object holds it as a reference.

using UnityEngine;
using Tsukimi;
public class ConversionsBoxing : TsukimiBehaviour
{
void Start()
{
int a = 1;
object o = a;
Debug.Log(o); // => 1
}
}
using UnityEngine;
using Tsukimi;
public class ConversionsUnboxing : TsukimiBehaviour
{
void Start()
{
object o = 1;
int a = (int)o;
Debug.Log(a); // => 1
}
}

is checks the type inside an object at runtime.

using UnityEngine;
using Tsukimi;
public class ConversionsIsGeneralType : TsukimiBehaviour
{
void Start()
{
object o = 1;
bool b = o is int;
Debug.Log(b); // => true
}
}
using UnityEngine;
using Tsukimi;
public class ConversionsReferenceWidening : TsukimiBehaviour
{
public Transform target;
void Start()
{
Component c = target;
Debug.Log(c == null); // => a runtime value
}
}
using UnityEngine;
using Tsukimi;
public interface IThing { int Get(); }
public struct Impl : IThing { public int Get() { return 1; } }
public class CvImplicitToInterface : TsukimiBehaviour
{
void Start()
{
Impl v = new Impl();
IThing t = v;
Debug.Log(t.Get()); // => 1
}
}

Conversion from object to a reference type

Section titled “Conversion from object to a reference type”

Takes a reference-type value assigned to object back to its original type.

using UnityEngine;
using Tsukimi;
public class ConversionsObjectToConcrete : TsukimiBehaviour
{
void Start()
{
object o = null;
Transform t = (Transform)o;
Debug.Log(t == null); // => a runtime value
}
}
using UnityEngine;
using Tsukimi;
public class CvNullLiteral : TsukimiBehaviour
{
void Start()
{
string s = null;
Debug.Log(s == null); // => true
}
}

Conversion from a type parameter to object

Section titled “Conversion from a type parameter to object”

The value of a type argument converts to object.

using UnityEngine;
using Tsukimi;
public class CvTypeParamImplicit : TsukimiBehaviour
{
void Start()
{
Debug.Log(ToObject<int>(1)); // => 1
}
private object ToObject<T>(T value)
{
return value;
}
}
using UnityEngine;
using Tsukimi;
public class CvDefaultLiteral : TsukimiBehaviour
{
void Start()
{
int a = default;
string s = default;
Debug.Log(a); // => 0
}
}
using UnityEngine;
using Tsukimi;
public struct Holder { public int V; }
public class CvImplicitNew : TsukimiBehaviour
{
void Start()
{
Holder h = new();
Debug.Log(h.V); // => 0
}
}
using UnityEngine;
using Tsukimi;
public class CvImplicitConditional : TsukimiBehaviour
{
void Start()
{
bool c = true;
long v = c ? 1 : 2;
Debug.Log(v); // => 1
}
}

Matching types across switch expression cases

Section titled “Matching types across switch expression cases”
using UnityEngine;
using Tsukimi;
public class CvSwitchExprConv : TsukimiBehaviour
{
void Start()
{
int k = 1;
long v = k switch { 1 => 10, _ => 20 };
Debug.Log(v); // => 10
}
}

ToString() turns a value into a string.

using UnityEngine;
using Tsukimi;
public class ConversionsToString : TsukimiBehaviour
{
void Start()
{
int a = 1;
string s = a.ToString();
Debug.Log(s); // => "1"
}
}
using UnityEngine;
using Tsukimi;
public class ConversionsParse : TsukimiBehaviour
{
void Start()
{
int a = int.Parse("1");
Debug.Log(a); // => 1
}
}