Type conversions
Forms that compile (23)
Section titled “Forms that compile (23)”| Syntax | Description | Note |
|---|---|---|
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 | Variables can’t be assigned the same way. |
(int)d | Explicit conversion to a narrower type | Converting 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 types | Going back from int to char requires a cast. |
Mode m = 0; | Conversion of the constant 0 to an enum | Other numeric types require a cast. |
(int)m | Conversion from an enum to a number | |
(Mode)a | Conversion from a number to an enum | |
(B)a | Conversion between enums | |
object o = a; | Boxing a value type | |
(int)o | Unboxing | |
o is int | Checking the type of the contents | It 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)o | Conversion from object to a reference type | |
string s = null; | Assigning null | |
return value; | Conversion from a type parameter to object | A 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 string | A number with no format specified takes the default format. |
int.Parse("1") | Reading from a string |
Forms that don’t compile (17)
Section titled “Forms that don’t compile (17)”| Syntax | Description | Error | Reason | Alternative |
|---|---|---|---|---|
int? a = 1; | A type meaning a value or null | TUKI0001, TUKI0101, TUKI0102 | runtime | Use a separate variable to hold whether a value is present |
int b = (int)a; | Extract the value from a value-or-null type | TUKI0102, TUKI0001, TUKI0099 | runtime | Same as above |
long? b = a; | Convert between value-or-null types (a lifted conversion) | TUKI0001, TUKI0101, TUKI0102 | runtime | Same as above |
dynamic d = 1; | Determine the type at runtime | TUKI0102, TUKI0099 | runtime | Write the type |
(long, long) b = a; | Convert between tuples element by element | TUKI0099 | not yet | Move the elements one at a time |
((int, int))a | Explicitly convert a tuple | TUKI0099 | not yet | Same as above |
(T)value | Convert from object back to a type parameter | TUKI0099 | undecided | Rewrite it without using a type parameter |
public static implicit operator float(Meters m) | Define your own implicit conversion | TUKI0001 | not yet | Write a conversion method and call it |
public static explicit operator int(Meters m) | Define your own explicit conversion | TUKI0001 | not yet | Same as above |
System.Action a = Helper; | Turn a method name into a delegate | TUKI0108 | runtime | Pass the method name and call it (SendCustomEvent) |
delegate(int x) { … } | Write a function inline as a value | TUKI0108, TUKI0001 | runtime | Same as above |
throw new System.Exception() | Throw an exception (as an expression or a statement) | TUKI0001, TUKI0101 | runtime | Represent failure with a return value or state |
System.FormattableString s = $"…"; | Hold an interpolated string as a formatting target | TUKI0102, TUKI0101, TUKI0099 | runtime | Build it as a string |
System.Span<int> s = a; | Borrow a view of a contiguous region | TUKI0102, TUKI0101, TUKI0099 | runtime | Use the array directly |
c as Transform | Become null if the conversion fails | TUKI0001 | not yet | If 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 Transform | Ask at runtime about a type that may have derived types | TUKI0001 | by design | If 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) | TUKI0001 | undecided | A 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 type | default, new(), ?:, and switch expressions are all converted to the type on the left |
| Converting between tuples | Not possible (TUKI0099). Declaring them is |
Same type and numbers
Section titled “Same type and numbers”Conversion to the same type
Section titled “Conversion to the same type”using UnityEngine;using Tsukimi;
public class CvIdentity : TsukimiBehaviour{ void Start() { int a = 1; int b = a; Debug.Log(b); // => 1 }}Implicit conversion to a wider type
Section titled “Implicit conversion to a wider type”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 }}Explicit conversion to a narrower type
Section titled “Explicit conversion to a narrower type”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 }}Conversion between char and numeric types
Section titled “Conversion between char and numeric types”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 }}Conversion of the constant 0 to an enum
Section titled “Conversion of the constant 0 to an enum”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 }}Conversion from an enum to a number
Section titled “Conversion from an enum to a number”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 }}Conversion from a number to an enum
Section titled “Conversion from a number to an enum”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 }}Conversion between enums
Section titled “Conversion between enums”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 }}Boxing
Section titled “Boxing”Boxing a value type
Section titled “Boxing a value type”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 }}Unboxing
Section titled “Unboxing”using UnityEngine;using Tsukimi;
public class ConversionsUnboxing : TsukimiBehaviour{ void Start() { object o = 1; int a = (int)o; Debug.Log(a); // => 1 }}Checking the type of the contents
Section titled “Checking the type of the contents”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 }}Reference types and interfaces
Section titled “Reference types and interfaces”Conversion to a base type
Section titled “Conversion to a base type”using UnityEngine;using Tsukimi;
public class ConversionsReferenceWidening : TsukimiBehaviour{ public Transform target;
void Start() { Component c = target; Debug.Log(c == null); // => a runtime value }}Conversion to an interface type
Section titled “Conversion to an interface type”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 }}Assigning null
Section titled “Assigning null”using UnityEngine;using Tsukimi;
public class CvNullLiteral : TsukimiBehaviour{ void Start() { string s = null; Debug.Log(s == null); // => true }}Type parameters
Section titled “Type parameters”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; }}Conversions determined by the target type
Section titled “Conversions determined by the target type”Writing default
Section titled “Writing default”using UnityEngine;using Tsukimi;
public class CvDefaultLiteral : TsukimiBehaviour{ void Start() { int a = default; string s = default; Debug.Log(a); // => 0 }}Creation with the type name omitted
Section titled “Creation with the type name omitted”using UnityEngine;using Tsukimi;
public struct Holder { public int V; }public class CvImplicitNew : TsukimiBehaviour{ void Start() { Holder h = new(); Debug.Log(h.V); // => 0 }}Matching types on both sides of ?:
Section titled “Matching types on both sides of ?:”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 }}Strings
Section titled “Strings”Conversion to a string
Section titled “Conversion to a string”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" }}Reading from a string
Section titled “Reading from a string”using UnityEngine;using Tsukimi;
public class ConversionsParse : TsukimiBehaviour{ void Start() { int a = int.Parse("1"); Debug.Log(a); // => 1 }}