From AS3 to C#, Part 1: Class Basics
This article is for the AS3 developer who’s decided to switch to Unity and doesn’t know the first thing about programming in C#. It’ll walk you through the basics of C# to get you oriented and productive.
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
First things first, C# files have the file extension .cs
instead of AS3’s .as
. Inside them you find the class
definitions that make up your app’s code, just like with AS3. For example, here’s a MyClass.cs
file:
class MyClass { }
Classes in C# have the same naming convention as with AS3: capitalize each word but leave the rest as lower-case. The actual class syntax is the same too, as you’ve likely noticed. Now let’s add a variable field:
class MyClass { int X; }
As you can see, variable fields are declared differently in C#. Instead of var x:int
, you use int X
. The naming convention says to capitalize public field variable names and lowercase the rest. I’ll talk about access specifiers more in a later article. For now, assume everything is public. Now let’s see a function:
class MyClass { void Foo() { } }
Functions are also different. You don’t use a function
keyword, the return type comes at the beginning instead of the end, and the naming convention says to capitalize the function name. Here’s a function with some parameters:
class MyClass { void Foo(int x, int y, int z) { } }
The variables go in between the parentheses—just like AS3—but they’re declared like field variables: type name
. However, these variables are different from field variables in naming since you start them with a lowercase letter. Just like AS3, you can have default parameters:
class MyClass { void Foo(int x = 1, int y = 2, int z = 3) { } }
Next up is a constructor function:
class MyClass { MyClass() { } }
Just like with AS3, there’s no need to declare a return type. In fact, you’re not allowed to give it a void
return type like you can with AS3. You also don’t use the function
keyword. However, you can have more than one constructor function. This is called “overloading” the function and each of them is referred to as “an overload”.
class MyClass { MyClass() { } MyClass(int x) { } MyClass(int x, int y, int z) { } }
Overloading is allowed on other functions, too:
class MyClass { void Foo() { } void Foo(int x) { } void Foo(int x, int y, int z) { } }
There are a couple of caveats to “overloading” to keep in mind. The compiler needs to be able to figure out which function you’re calling, so two rules are put in place. First, you can’t have two functions with the same parameters:
class MyClass { void Foo(int x, int y, int z) { // do some stuff } void Foo(int x, int y, int z) { // do some different stuff } }
This includes functions that would be the same if the caller left out one or more default parameters:
class MyClass { void Foo(int x, int y, int z) { // do some stuff } void Foo(int x, int y, int z, int w = 0) { // do some different stuff } }
The other rule is that you can’t “overload” the functions by their return type:
class MyClass { int Foo(int x, int y, int z) { return 0; } uint Foo(int x, int y, int z) { return 0; } }
Keep these two simple rules in mind, and you can overload to your heart’s content.
Within a class you can use this
just like in AS3, but not within static functions. Just like in AS3, you just need to add the static
keyword:
class MyClass { static void Foo() { } }
Static class variables are the same way:
class MyClass { static int X; }
Now that we’ve seen how to declare a class, and variables, functions, and constructor functions in a class, let’s see how to use them:
void SomeCode() { // Call the default constructor (i.e. no arguments) MyClass mc = new MyClass() // Call a different constructor mc = new MyClass(5); // Call a function mc.Foo(); // Call an overloaded function mc.Foo(1, 2, 3); // Call a static function MyClass.Foo(); // Get a field variable mc.X; // Set a field variable mc.X = 1; // By the way, single-line comments are the same... /* ... and so are multi-line comments */ }
All of that should look extremely similar to AS3. One detail is that the local variable mc
starts with a lower case letter just like the function’s parameters.
Now let’s discuss access modifiers. The normal public
, private
, and protected
modifiers are just like in AS3 and have similar syntax. Just add it before the return type of a function, type of a field variable, or class
keyword of the class:
public class MyClass { private int X; protected void Foo() { } }
There is also an internal
access modifier, which has the same name but a slightly different meaning than in AS3. In AS3, internal
means “only accessible by this class and other classes in the same package“. In C#, internal
means “only accessible by this class and other classes in the same assembly“. I’ll cover assemblies at some later date, but think of them for now as all the classes compiled together into one binary. Lastly, there is a protected internal
access modifier which is a combination of both protected
and internal
.
Lastly, here’s a comparison between C# and AS3 covering everything in this article:
//////// // C# // //////// ///////////////// // Declaration // ///////////////// // Class public class MyClass { // Field variable public int X; // Class variable static public int Y; // Default constructor public MyClass() { } // Overloaded constructor public MyClass(int x) { } // Instance function public void Foo() { } // Overloaded instance function public void Foo(int x) { } // Class function static public void Goo() { } // Overloaded class function static public void Goo(int x) { } } /////////// // Usage // /////////// // Call the default constructor MyClass mc = new MyClass() // Call a different constructor mc = new MyClass(5); // Call an instance function mc.Foo(); // Call an overloaded instance function mc.Foo(1); // Call a static function MyClass.Goo(); // Call an overloaded static function MyClass.Goo(1); // Get an instance variable mc.X; // Set an instance variable mc.X = 1; // Get a class variable MyClass.Y; // Set a class variable MyClass.Y = 1; // Single-line comment /* Multi-line comment */
///////// // AS3 // ///////// ///////////////// // Declaration // ///////////////// // Class public class MyClass { // Field variable public var x:int; // Class variable static public var y:int; // Default constructor public function MyClass() { } // Overloaded constructor // {not supported} // Instance function public function foo(): void { } // Overloaded instance function // {not supported} // Class function static public function goo(): void { } // Overloaded class function // {not supported} } /////////// // Usage // /////////// // Call the default constructor var mc:MyClass = new MyClass() // Call a different constructor mc = new MyClass(5); // Call an instance function mc.foo(); // Call an overloaded instance function // {not supported} // Call a static function MyClass.goo(); // Call an overloaded static function // {not supported} // Get an instance variable mc.x; // Set an instance variable mc.x = 1; // Get a class variable MyClass.y; // Set a class variable MyClass.y = 1; // Single-line comment /* Multi-line comment */
This concludes the first part of the From AS3 to C# series. Upcoming articles (starting next week) will cover more advanced topics, including features that don’t exist at all in AS3. Stay tuned!
Spot a bug? Have a question or suggestion? Post a comment!
#1 by Harry248 on July 21st, 2014 ·
Really looking forward to your C# posts! Learned a lot from your AS3 articles over the years. Not really interested in Unity but Xamarin which also uses C#.
#2 by jackson on July 21st, 2014 ·
Xamarin has piqued my interest, too. I’m planning to carve out some time in the near future to play around with it. I may even post an article or two if there’s enough interest.
#3 by Harry248 on July 23rd, 2014 ·
Great to hear! Xamarin catched my attention with the release of Xamarin.Forms. Beforehand the ratio of shared code was just to little.
Some suggestion for your next posts:
Actionscript Function References vs. C# Delegates / Lambda-Expressions
Actionscript Events vs. C# Events (this was the most strange for me, coming from AS3…)
Actionscript Vector. vs. C# List
Actionscript Dictionary vs. C# Dictionary
C# Generic Classes/Methods
C# Async / Await (this impressed me most apart from Linq)
Linq
#4 by jackson on July 23rd, 2014 ·
Xamarin.Forms is exactly what got me interested in it, too. Since it’s not really for games, the UI of a non-game app is going to be huge. The idea of re-writing the UI for each platform seems like it discards a lot of the purpose of an abstraction layer like Xamarin in the first place.
Thanks for the article suggestions. I’ve already got some of those planned as I’ll definitely be doing lots of comparing AS3 to C# in this series.
#5 by Phil on July 22nd, 2014 ·
Great post, sad to see you leave As3 but C# is a great language even if Unity has it’s flaws.
One thing though it seems like you are accessing private variables outside the scope of a class. Technically this should not be possible in either language, if the fields are public then it’s all good of course.
#6 by jackson on July 22nd, 2014 ·
Thanks for pointing out the issue with the
private
variables. I’ve switched them to public in the article. I’ve also renamed the class variable toY
so as to not have a duplicateX
.#7 by 7-by on July 24th, 2014 ·
Hi, very nice article. But i have one question
In this code for C#
you don’y use the
static
keyword. Why? Is it right? It looks like you can overload method without thestatic
#8 by jackson on July 24th, 2014 ·
Good catch! I’ve updated the article to add the
static
keyword to the overloadedGoo
function.#9 by Fixxxxx on July 31st, 2014 ·
Hi,
I find something wrong.
It’s should be,
#10 by jackson on July 31st, 2014 ·
Thanks for spotting this typo. I’ve updated the article with a fix.
#11 by Bernd on March 2nd, 2015 ·
Hi Jackson,
I am bit late to the party but still wanna ask something related to the article here. I appears to me that you say that all class members, fields and methods should begin with capital case and all local variables with lower case. The C# Examples on MSDN user lower case for class fields. Also the predominant style adapted by Unity is lower case for fields.
When it comes to Properties MSDN starts them with a capital letter, while Unity also uses lower case, while your examples go with the MSDN way.
This is a bit confusing, when trying to adapt a coherent style.
#12 by jackson on March 2nd, 2015 ·
Thanks for pointing out the discrepancies. In this article I hadn’t yet gotten to public and private access specifiers, but the naming convention depends on them. You’re not supposed to use public fields, but when you do they’re named like public properties: PascalCase. Private variables are always named in camelCase.
Unity is, unfortunately, a huge violator of this rule. They name public variables and fields in camelCase unlike almost every other C# API. If you want, you could adopt their naming convention over the standard C# one to fit in better with their API. Personally, I prefer to go with the standard naming convention to fit in better with other APIs like .NET. You’ll unavoidably use both, so your code will have to choose one way or the other. It’s not so bad though, as long as you’re consistent with one or the other.
Thanks again for spotting this. I’ve updated the article to clarify. If you spot anything else on this or any other article, please post a quick comment to let me know.