Today we continue the series by wrapping up C#’s class/interface/struct/enum system with a discussion of where to put them all. We’ll focus on package/namespace, organizing types into files, and some details of using/import.

Table of Contents

In AS3, there are classes, interfaces, and functions but not structures or enums. You can choose to put them in a package or not. That looks like this:

// MyClass.as - not in a package
package
{
    class MyClass {}
}
 
// MyInterface.as - not in a package
package
{
    interface MyInterface {}
}
 
// foo.as - not in a package
package
{
    function foo(): void {}
}
 
// com/jacksondunstan/examples/MyClass.as - in a package
package com.jacksondunstan.examples
{
    class MyClass {}
}
 
// com/jacksondunstan/examples/MyInterface.as - in a package
package com.jacksondunstan.examples
{
    interface MyInterface {}
}
 
// com/jacksondunstan/examples/foo.as - in a package
package com.jacksondunstan.examples
{
    function foo(): void {}
}

To gain access to all the contents of a package, you use import packagename.* at the start of the package:

package
{
    import com.jacksondunstan.examples.*;
 
    public class Example
    {
        // Now use something from the package
        private var myc:MyClass;
    }
}

Or you can gain access to just one class, interface, or function by using import packagename.itemname:

package
{
    import com.jacksondunstan.examples.MyClass;
 
    public class Example
    {
        // Now use the imported item from the package
        private var myc:MyClass;
    }
}

Or you can skip the import and explicitly qualify your access by using fully-qualified names:

package
{
    public class Example
    {
        // Use the fully-qualified item from the package
        private var myc:com.jacksondunstan.examples.MyClass;
    }
}

If the class, interface, or function you want to use isn’t in a package, there’s no way to explicitly import it. It is simply globally available. So the Example class can be used by the MyClass class:

package com.jacksondunstan.examples
{
    class MyClass
    {
        private var ex:Example;
    }
}

C# does this a little differently. The namespace keyword replaces package. Instead of using package with no name, you can just omit the namespace altogether.

// MyClass.cs - not in a namespace
class MyClass {}
 
// MyInterface.cs - not in a namespace
interface MyInterface {}
 
// MyEnum.cs - not in a namespace
enum MyEnum {}
 
// MyStruct.cs - not in a namespace
struct MyStruct {}
 
// com/jacksondunstan/examples/MyClass.cs - in a namespace
namespace com.jacksondunstan.examples
{
    class MyClass {}
}
 
// com/jacksondunstan/examples/MyInterface.cs - in a namespace
namespace com.jacksondunstan.examples
{
    interface MyInterface {}
}
 
// com/jacksondunstan/examples/MyEnum.cs - in a namespace
namespace com.jacksondunstan.examples
{
    enum MyEnum {}
}
 
// com/jacksondunstan/examples/MyStruct.cs - in a namespace
namespace com.jacksondunstan.examples
{
    struct MyStruct {}
}

The paths for each of these files are just suggestions with C#. You can put them anywhere, but the convention is for the paths to match the namespace names like in AS3. For usage, the using keyword replaces import and you omit the .* portion when importing a whole package/namespace:

using com.jacksondunstan.examples;
 
namespace myexamples
{
    public class Example
    {
        // Now use something from the namespace
        private MyClass myc;
    }
}

If you have a static class, you can import just that from a namespace by adding its name to the using statement:

using com.jacksondunstan.examples.MyStaticClass;

You can also move the using statements inside your namespace for a subtle difference in behavior:

namespace myexamples
{
    using com.jacksondunstan.examples;
 
    public class Example
    {
        // Now use something from the namespace
        private MyClass myc;
    }
}

If the using is outside the namespace myexamples then the myexamples namespace will be searched for MyClass before com.jacksondunstan.examples is. It’s the other way around if you put the using statement inside the namespace examples.

Another feature of using is to create aliases. This is useful when you’ve got identically-named classes in multiple namespaces and would rather not use fully-qualified names.

using SystemObject = System.Object;
using UnityObject = UnityEngine.Object;
 
class Example
{
    private SystemObject system;
    private UnityObject unity;
}

These have essentially created a new type which is an alias for a type in another namespace.

Like AS3, you can also skip the using and use fully-qualified names if you’d rather go that route:

namespace myexamples
{
    public class Example
    {
        // Now use something from the namespace
        private com.jacksondunstan.examples.MyClass myc;
    }
}

Unlike AS3’s global accessibility of classes, interfaces, and functions that aren’t in a package, C# makes you explicitly qualify your access using the global:: prefix:

namespace com.jacksondunstan.examples
{
    class MyClass
    {
        private var global::Example ex;
    }
}

In AS3, you can only have one public class or interface in a file. The others need to be local to that class only:

public class MyClass
{
    private var helper:HelperClass;
}
internal class HelperClass
{
}

C# has no such prohibition. You can have as many public types as you want in a single file:

public class MyClass
{
    private HelperClass helper;
}
public class HelperClass
{
}

You can also nest your classes, interfaces, and structs within each other:

public class MyClass
{
    public class HelperClass
    {
    }
 
    private HelperClass helper;
}

To use a nested class from within the class, use it like normal:

HelperClass helper = new HelperClass();

To use it from outside the class, just qualify it with a . like you’d do with namespaces:

MyClass.HelperClass helper = new MyClass.HelperClass();

The nested classes get visibility into the class their nested in, so they do things like write to private variables:

public class MyClass
{
	private static int health;
 
	public class Helper
	{
		public void Foo()
		{
			health += 2;
		}
	}
}

Finally, let’s summarize this all with a quick comparison between C# and AS3 for everything discussed today:

////////
// C# //
////////
 
// Type outside of a package
public class MyClass {}
 
 
 
 
// Type inside a package
namespace mypackage
{
	public class MyClass
	{
		// Nest a type
		public class NestedClass {}
	}
}
// Another type in the same file
public class HelperClass {}
 
// Get access to the types in a package
using mypackage;
 
// Get access to a type in a package - static classes only in C#
using mypackage.MyStaticClass;
 
// Create an alias for a type in a package
using UnityObject = UnityEngine.Object;
 
// Explicitly use a type in a package
mypackage.MyClass myc;
 
// Explicitly use a type outside of a package
global::MyClass myc;
/////////
// AS3 //
/////////
 
// Type outside of a package
package
{
	public class MyClass {}
}
 
// Type inside a package
package mypackage
{
	public class MyClass
	{
		// Nest a type
		// {impossible in AS3}
	}
}
// Another type in the same file: non-public only
internal class HelperClass {}
 
// Get access to the types in a package
import mypackage.*;
 
// Get access to a type in a package
import mypackage.MyClass;
 
// Create an alias for a type in a package
// {impossible in AS3}
 
// Explicitly use a type in a package
var myc:mypackage.MyClass;
 
// Explicitly use a type outside of a package
global::MyClass myc;

This wraps up C#’s object model. Next week we’ll move on to the remainder of the syntax (types, casts, etc.). Stay tuned!

Continue to Part 14

Spot a bug? Have a question or suggestion? Post a comment!