From AS3 to C#, Part 3: AS3 Class Parity
Picking up from last time, today we’ll finish off classes in C# from an AS3 perspective in preparation for next week when we delve into all-new concepts that aren’t in AS3 at all. Read on to learn the C# way to implement getters and setters, final functions and classes, const variables, and packages.
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 up are getters and setters. As a refresher, here’s how they look in AS3:
class Person { private var _name:String; public function get name(): String { return _name; } public function set name(n:String): void { _name = n; } }
Now let’s see the equivalent code in C#:
class Person { private String _name; public String Name { get { return _name; } set { _name = value; } } }
Instead of being declared as two functions, the getter and setter are declared as a single variable. That variable doesn’t end with a semicolon (;
) but instead a curly braces block containing to parts: get{}
and set{}
. Those parts are the getter and setter functions. Inside the setter you get access to a new keyword: value
. This means “the value to set” because you never declared it as a parameter, unlike AS3. Other than this syntactical difference, everything else works the same.
C# also provides a shorthand to avoid most of this typing for simple getters and setters. Behold:
class Person { public String Name { get; set; } }
Using this will automatically create the _name
variable and the getter and setter functions just as they were in the previous example. But what if you didn’t want a setter? Just leave it out:
class Person { public String Name { get; } }
However, you probably want at least the Person
class to be able to set it. In that case, just declare it private:
class Person { public String Name { get; private set; } }
Finally, one bit of terminology. The field of the class that does the getting and/or setting (Name
) is called a “property” in C# lingo. The variable it gets and sets (_name
) is called the “backing field”.
Next let’s talk about “final” functions that can’t be overridden.
class Person { final function print(): void { trace("I'm a Person"); } } class MyPerson extends Person { // illegal override function print(): void { trace("I'm not just a Person, I'm a MyPerson too"); } }
C# has the same concept with its sealed
keyword again:
class Person { sealed void Print() { Debug.Log("I'm a Person"); } } class MyPerson : Person { // illegal override void Print() { Debug.Log("I'm not just a Person, I'm a MyPerson too"); } }
Now on to packages in AS3:
package com.jacksondunstan.examples { class Person { } }
C# simply calls a package a namespace instead:
namespace com.jacksondunstan.examples { class Person { } }
To give access to the classes in a package to a .as
file, you import
the package:
import com.jacksondunstan.examples; class Printer { function print(person:Person): void { trace("person has name: " + person.name); } }
In C#, you say that you’re using
the namespace:
using com.jacksondunstan.examples; class Printer { void Print(Person person) { Debug.Log("person has name: " + person.name); } }
Finally today, let’s talk about const
fields in AS3. This is how you make a field that can’t be changed after it’s declared:
class Person { private static const MIN_TEEN_AGE:int = 13; private static const MAX_TEEN_AGE:int = 19; var age:int; function IsTeen(): Boolean { return age >= MIN_TEEN_AGE && age <= MAX_TEEN_AGE; } }
Here’s how it’d work in C#:
class Person { private const int MinTeenAge = 13; private const int MaxTeenAge = 19; int Age; bool IsTeen() { return Age >= MinTeenAge && Age <= MaxTeenAge; } }
One important difference is that in C# you can only make basic types (e.g. int
) and strings const
. This is because the field will not actually exist. Instead, it’s erased and inlined everywhere that it’s used. This means that it’s inherently a static
variable, so you don’t need to declare it as static
. The Person
class in C# will actually be compiled like this:
class Person { int Age; bool IsTeen() { return Age >= 13 && Age <= 19; } }
In AS3, the const
keyword is just for compile-time checking and won’t result in any inlining. If you want that behavior in C# or need to use non-basic types (e.g. Person
), you need to use the readonly
keyword instead:
class Person { static readonly Person Newborn = new Person(0); readonly int Age; Person(int age) { Age = age; } }
Here we see two readonly
fields. The Newborn
field is declared static
since readonly
fields are not necessarily so. It’s initialized where it’s declared just like you must do with const
fields in AS3. However, the Age
field is readonly
but not static
. It’s initialized in the construct, where it must be initialized in C#.
Lastly, here’s a comparison between C# and AS3 covering everything in this article:
//////// // C# // //////// // Collection of classes being used by this file using org.apache.coolstuff; // Collection of classes namespace com.jacksondunstan.examples { class Person { // Complex getters and setters private String _name; String Name { get { return _name; } set { _name = value; } } // Simple getters and setters int Age { get; set; } // Read-only field readonly int ID; // Inlined field const int AdultAge = 18; // Function that can't be overridden sealed void Print() { Debug.Log("Name: " + name + ", ID: " + ID); } } }
///////// // AS3 // ///////// // Collection of classes being used by this file import org.apache.coolstuff; // Collection of classes package com.jacksondunstan.examples { class Person { // Complex getters and setters private var _name:String; function get name(): String { return _name; } function set name(value:String): void { _name = value; } // Simple getters and setters // {not supported. use complex instead.} // Read-only field const var ID:int; // Inlined field // {not supported. use compile-time constants via command-line instead.} // Function that can't be overridden final function print(): void { trace("Name: " + name + ", ID: " + ID); } } }
Next time we’ll start to cover concepts that simply aren’t available in AS3. Stay tuned!
Spot a bug? Have a question or suggestion? Post a comment!
#1 by Tommy on August 4th, 2014 ·
So if I declare a variable like so : public String Name { get; set; } will I still be able to use the private variable _name? Or do I still have to declare it right before with private String _name;
Also how does the naming convention works for variables that have getters and setters, if they have multiple words in their name? So far im guessing like so : private String _nameFirstAdult;
String NameFirstAdult {get;set;}
But maybe is it _name_first_adult or _namefirstadult instead?
#2 by jackson on August 4th, 2014 ·
When you declare this:
You’ve technically declared a “property” not a “variable”. The compiler will then generate a “backing variable” of type
String
to get and set when it implements theget{}
andset{}
blocks. The name it gives to this “backing variable” is not specified and you’re not allowed to directly use it by guessing. I just tried using that property and also declaring_name
andname
variables and there was no problem. It seems that the compiler will always generate a unique name behind the scenes.As for naming convention, Microsoft says:
However, it seems that there are several popular styles: (in order of popularity I’ve seen)
#3 by Merlin on August 4th, 2014 ·
> today we’ll finish off classes in C#
What about the difference between “class” and “struct” ?
When I tried “unity”, for me was a big surprise:
#4 by jackson on August 5th, 2014 ·
The rest of the sentence says—probably unclearly—that today’s article just finishes up the part of C# classes that have equivalents in AS3:
However, I’ve already realized that I forgot class constructors:
So there will be at least some coverage of forgotten items in the future. Structs and other C#-only features will be covered in upcoming articles. They’re currently in a bucket of about 8 more class/struct-related topics just labeled “advanced”, so they could be in the next article. If not, they’ll be shortly thereafter. Stay tuned!
#5 by Bernd on March 4th, 2015 ·
Your Code examples always have the string type starting with a capital S. Monodevelop codecompletes it with a lower S. Is this a spelling error?
#6 by jackson on March 4th, 2015 ·
Either is valid, but
string
is more common when declaring a type. I used the uppercase version in this article because I hadn’t yet gotten to the built-in types in part 14 of the series. In that part I explain thatstring
is a synonym forSystem.String
just asint
is a synonym forSystem.Int32
.#7 by Bernd on April 7th, 2015 ·
I wonder whats the point in using the “short form” property
when you can just use
as a public field? I know its better to encapsulate and such, but if I have a value which is basically just a fixed value and no operations on it when getting and setting it, why the detour via a property?
Even if I decide to do some operations on it later and therefore want to change it to a property I can simply change it by adding the logic. The Api of the class stays the same.
#8 by jackson on April 7th, 2015 ·
That’s certainly an option and you’re right that the API would appear to stay the same. I can only think of a couple of reasons to prefer the property to the field off the top of my head. First, properties are functions that can be
virtual
so derived classes canoverride
them. Of course you could change your public variable to a property at the point where you want to do that, like with your example. The other reason is that fields and properties are accessed differently using the reflection APIs inSystem.Reflection
. If you don’t use reflection, then this obviously won’t matter.Performance-wise, there’s very little difference between fields and properties. That may change the question around to be “why not use properties?”
#9 by Dev Dee on September 22nd, 2016 ·
Hey Jack,
Noticed a typo in the code for the sealed function in C#
It reads –
class MyPerson extends Person
but it should be –
class MyPerson : Person
Thanks for posting all these useful articles!
#10 by jackson on September 22nd, 2016 ·
Thanks for pointing out the typo. I’ve updated the article with the fix.
Glad you’re enjoying the articles!
#11 by Jamie on September 14th, 2020 ·
I love C# its such a beautiful language. You can tell its had tons of money poured into it over the years. VS is just amazing too.
Great tutorial as always.
Take care
Jamie