From AS3 to C#, Part 15: Loops, Casts, and Operators
As with types and variables, there is a lot of subtlety in the differences between AS3 and C# when it comes to loops, casts, and operators. As core parts of the language, it’s important that we know all the little details of our most fundamental tools. Read on to learn what they have in common, what new operators C# offers, and what operators C# doesn’t have.
Table of Contents
- From AS3 to C#, Part 1: Class Basics
- From AS3 to C#, Part 2: Extending Classes and Implementing Interfaces
- From AS3 to C#, Part 3: AS3 Class Parity
- From AS3 to C#, Part 4: Abstract Classes and Functions
- From AS3 to C#, Part 5: Static Classes, Destructors, and Constructor Tricks
- From AS3 to C#, Part 6: Extension Methods and Virtual Functions
- From AS3 to C#, Part 7: Special Functions
- From AS3 to C#, Part 8: More Special Functions
- From AS3 to C#, Part 9: Even More Special Functions
- From AS3 to C#, Part 10: Alternatives to Classes
- From AS3 to C#, Part 11: Generic Classes, Interfaces, Methods, and Delegates
- From AS3 to C#, Part 12: Generics Wrapup and Annotations
- From AS3 to C#, Part 13: Where Everything Goes
- From AS3 to C#, Part 14: Built-in Types and Variables
- From AS3 to C#, Part 15: Loops, Casts, and Operators
- From AS3 to C#, Part 16: Lambdas and Delegates
- From AS3 to C#, Part 17: Conditionals, Exceptions, and Iterators
- From AS3 to C#, Part 18: Resource Allocation and Cleanup
- From AS3 to C#, Part 19: SQL-Style Queries With LINQ
- From AS3 to C#, Part 20: Preprocessor Directives
- From AS3 to C#, Part 21: Unsafe Code
- From AS3 to C#, Part 22: Multi-Threading and Miscellany
- From AS3 to C#, Part 23: Conclusion
Let’s start with loops, which are largely the same in C# as they are in AS3. The standard three-part for
loop is exactly the same:
// AS3 for (var i:int = 2; i < 4; ++i) { // ... do something with i }
// C# for (int i = 2; i < 4; ++i) { // ... do something with i }
So is the while
loop:
// AS3 var i:int = 2; while (i < 4) { // ... do something with i ++i; }
// C# int i = 2; while (i < 4) { // ... do something with i ++i; }
So is do-while
:
// AS3 var i:int = 2; do { // ... do something with i ++i; } while (i < 4);
// C# int i = 2; do { // ... do something with i ++i; } while (i < 4);
AS3’s for-each
loop is only slightly different between the two:
// AS3 for each (var val:int in someIntegers) { // ... do something with val }
// C# foreach (int val in someIntegers) { // ... do something with val }
The for-each
loop in AS3 can loop over any Array
, Vector
, Object
, or Proxy
that’s implemented the appropriate function. In C#, the foreach
loop can loop over any array (e.g. int[]
) or class implementing the IEnumerable
interface.
All of these loops in both languages support the break
and continue
statements. However, C# does not support breaking to a label like you can do in AS3:
var found:Boolean = false; outerLoop: for (var row:int = 0; row < numRows; ++i) { for (var col:int = 0; col < numCols; ++i) { if (table[row][col] == valToFind) { found = true; break outerLoop; } } }
In C#, break
can’t take a label to break to. You need to use goto
to do that sort of thing. This leads us to the final kind of “loop” that is possible thanks to goto
. Build your own loop!
int i = 0; LoopStart: Debug.Log(i); ++i; if (i < 3) goto LoopStart; // output: // 0 // 1 // 2
Of course you should normally use a normal for
, while
, do-while
, or foreach
loop, but goto
gives you flexility for those very rare cases where none of them are ideal. More importantly, it restores your ability to break out of nested loops and can be a viable way to jump around functions, such as to consolidate error handling code.
Next we move on to casts. These too are similar to AS3, but with some minor differences. In AS3, you get a function-style cast:
var square:Square = Square(shape);
If the cast fails, a TypeError
will be thrown. If you’d rather just get null
instead of a thrown Error
then you can use the other cast: as
var square:Square = shape as Square;
Instead of a function-style cast, C# moves the parentheses so that they surround the type you’re casting to rather than the object being casted:
Square square = (Square)shape;
This will throw an InvalidCastException
if the cast fails. Like in AS3, there is an as
keyword that returns null
if the cast fails:
Square square = shape as Square;
Unlike AS3, some types in C# can’t be assigned null
. This means that the cast can’t be used on basic types like int
and float
or any struct
. It can, however, be used on any nullable type like int?
.
Now for the many, many operators in AS3 and C#. Most of them are the same and don’t need any coverage here; you can probably guess what +
does in both languages. There are some differences though. For example, there are two operators to shift the bits of an int
or uint
in AS3:
var signedShift:int = val >> 3; var unsignedShift:int = val >>> 3;
The difference between the two is that the >>>
operator does not preserve the sign value of the integer being shifted. In contrast, C# lacks the >>>
operator completely. The same goes for the >>>=
operator. Instead, you just use the >>
operator on unsigned integers like uint
and byte
.
Similarly, AS3 has a “strict equality” operator: ===
var nullVal:* = null; var undefinedVal:* = undefined; var equal:int = nullVal == undefinedVal; // true var strictlyEqual:int = nullVal === undefinedVal; // false
C# has no such operator. Instead, you can control type conversion via explicit
and implicit
conversion operators.
AS3 has two operators for logical comparisons with assignment that are also not present in C#:
myBool &&= otherBool; myBool ||= otherBool;
Just like with +=
and +
, you can write this without the &&=
or ||=
operators:
myBool = myBool && otherBool; myBool = myBool || otherBool;
The in
operator is also missing in C#. AS3 provides it so you can check if a value is a property of an object:
var hasProp:Boolean = "first_name" in myJSON;
The in
operator only applies to anonymous classes in C#, which are usually rare. Regardless, you’ll have to try accessing the property and catch an exception if it doesn’t exist:
dynamic person = new { first_name = "Jackson" }; try { bool hasProp = person.first_name; } catch (Exception ex) { // property not found }
Similarly, in AS3 you can index into any object with yet-another operator that isn’t in C#:
var prop:String = myJSON["first_name"];
Or for plain Object
or untyped (*
) variables, you can use the dot (.
) operator like you would in C#:
var prop:String = myJSON.first_name;
In AS3, however, you won’t get an exception like you would in C#. You’ll just get undefined
returned. This can be a bit misleading if the value of the property is actually undefined
. For example:
var hasProp:Object = { first_name: undefined }; var noProp:Object = { }; var propHas:String = hasProp.first_name; // prop found, undefined var propHasNot:String = noProp.first_name; // prop NOT found, undefined
This is part of why AS3 has the in
operator. C# instead throws an exception when the property is not found and returns what it actually is—not undefined
—if it isn’t.
Finally, two areas of AS3’s syntax simply don’t exist in C#. First are regular expressions like in AS3:
var regexp:RegExp = /[a-Z]*/;
This has been replaced with the Regex
class, much like AS3’s RegExp
class. Second is AS3’s inline support for XML:
var doc:XML = <class><students><student><first>Jackson</first><last>Dunstan</last></student></students></class>;
Along with the support for defining XML in code, C# lacks all the XML operators. This includes looping over XML elements, the descendant (..
) operator, and the attribute (@
) operator with its XML expression support. XML is, in short, not a first-class member of C#.
Before moving on to the few operators in C# that aren’t in AS3, there is one operator that is the similar in both languages but has a few differences. That is the “null coalescing” operator. Here it is in AS3:
name ||= "Unknown";
If name
is anything that evaluates to false
, it’ll get assigned "Unknown"
. Otherwise, it doesn’t change. C# allows you to use this with or without assignment to the first operand like so:
name = name ?? "Unknown"; string otherName = name ?? "Unknown";
As for operators that C# has that AS3 does not, there are only a few. First, you can get the Type
—like AS3’s Class
—of an object using typeof
:
Type type = typeof("Hello"); // System.String
You can also use it with generic type parameters:
T Add<T>(T a, T b) { Type type = typeof(T); Debug.Log(type); return a + b; } Add(5u, 10u); // returns 15u, prints System.Uint32 Add(5f, 10f); // returns 15f, prints System.Single
The final operators for today are a pair of operators to control integer overflow. First, you can request a System.OverflowException
to be thrown if any integer overflows using the checked
keyword. There are two forms:
int twoBillion = 2000000000; checked(twoBillion + twoBillion); // exception checked { int oneBillion = 1000000000; int result = oneBillion + oneBillion; // 2000000000 int twoBillion = 2000000000; result = twoBillion + twoBillion; // exception }
You can also suppress the exception and accept the overflowed value using the unchecked
operator. It’s syntax is the same:
int twoBillion = 2000000000; unchecked(twoBillion + twoBillion); // -294967296 unchecked { int oneBillion = 1000000000; int result = oneBillion + oneBillion; // 2000000000 int twoBillion = 2000000000; result = twoBillion + twoBillion; // -294967296 }
To sum up, the following side-by-side code shows the differences between the two languages’ loops, casts, and operators:
//////// // C# // //////// // Loop over values foreach (string name in names) {} // Break out of nested loop while (true) while (true) goto AfterLoop; AfterLoop: // Throw exception if cast fails Square square = (Square)shape; // Unsigned shift // {unavailable in C#, use normal shift with unsigned int instead} // Logical compare with assignment // {unavailable in C#, use two operators instead} // Check for dynamic property // {unavailable in C#, get and check for exception instead} // Get dynamic property dynamicObject.someProperty; // Define regular expression // {unavailable in C#, use Regexp class instead} // Define XML document // {unavailable in C#, use XmlDocument class instead} // Access XML document // {unavailable in C#, use XmlDocument class' API instead} // Get first non-null value name = name ?? "Default"; // Get variable's type Type t = typeof(someVar); // Throw exception for integer overflow checked(a + b); checked { a + b; }
///////// // AS3 // ///////// // Loop over values for each (var name:String in names) {} // Break out of nested loop AfterLoop: while (true) while (true) break AfterLoop; // Throw exception if cast fails var square:Square = Square(shape); // Unsigned shift result = val >>> 3; // Logical compare with assignment myBool &&= otherBool; myBool ||= otherBool; // Check for dynamic property var hasFirstName:Boolean = "first_name" in myJSON; // Get dynamic property dynamicObject.someProperty; dynamicObject["someProperty"]; // Define regular expression var letters:RegExp = /[a-Z]+/; // Define XML document var page:XML = /<html><head></head><body><h1 id="title">My Page</h1></body></html>/; // Access XML document page.body.title.h1; page.body.title.h1.@id; // ... and others // Get first non-null value name||= "Default"; // Get variable's type // {unavailable in AS3, use "prototype" or describeType() instead} // Throw exception for integer overflow // {unavailable in AS3} //
Next week we’ll continue the series with even more of the kind of code you can put in your functions. Stay tuned!
Spot a bug? Have a question or suggestion? Post a comment!
#1 by slava on February 9th, 2016 ·
// AS3 //: AfterLoop == OuterLoop ?:)
#2 by jackson on February 9th, 2016 ·
I’ve updated the article to fix the typo. Thanks for letting me know!
#3 by Stan on October 23rd, 2017 ·
C3 -> C#
#4 by Stan on October 23rd, 2017 ·
dynamic person = new [] { first_name = “Jackson” };
[] seems incorrect here
#5 by jackson on October 23rd, 2017 ·
Thanks for catching more typos. I’ve updated the article with both of these fixes.