Skip to content

Conversions

SyntaxDescription
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 range
(int)dExplicit conversion to a narrower type
int a = c; char d = (char)a;Conversion between char and numeric types
Mode m = 0;Conversion of the constant 0 to an enum
(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 contents
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 object
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 string
int.Parse("1")Reading from a string
SyntaxDescriptionErrorReasonInstead
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 yetReceive it with a union type pattern (s switch { Box b => … })
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)TUKI0001undecidedGeneric interfaces only work for declaration and implementation. Rewrite it in a form that doesn’t use it as a value.
The type meaning “a value or null” can’t be used. That type doesn’t exist in the runtime (TUKI0102). The form of ?. that returns a value type doesn’t compile either, because the result would be this type.

Conversions determined by the target type apply to default, new(), ?:, and switch expressions. All of them convert to the type on the left-hand side.

Tuples can be declared, but conversion between tuples isn’t possible (TUKI0099).

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 the range can be assigned to a narrower type without a cast. A variable can’t be assigned the same way.

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 Numerics. For conversion from a floating-point type to an integer type, a value outside the range stops execution.

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 a cast. Converting back from int to char requires 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
}
}

Only the constant 0 converts implicitly. Other numbers require a cast.

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
}
}

When a value type is placed into object, it’s held 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 of object’s contents at runtime. This works only when the value is object and the type being checked is a number, bool, char, or string.

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”

Convert a reference-type value held in 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”

A type parameter’s value converts to object. Converting from object back to a type parameter can’t be written.

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() converts a value to a string. A number with no specified format uses the default format.

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
}
}