In the previous chapter, we looked at the user interface guidelines for WP7 applications. We will now dive deeper into what it takes to implement a WP7 application.
In this chapter, we will look at the various C# features that map to the most common Objective-C features. We will provide code snippets which will ease your way into C# code. We will point to the key C# features that help you write safe code and enhance productivity.
Introduction to Managed Programming
WP7 only supports managed programming in C# or VB.NET. Before we jump into the details of C#, let us briefly review managed programming.
The C# compiler (and similarly, the VB compiler) compiles the C# (or VB.NET) code into an intermediate language (IL) bytecode and metadata. The Common Language Runtime (CLR) executes the byte code. It uses metadata to manage type safety, exception handling, array bounds, etc. The CLR also manages memory and performs garbage collection. In contrast, Objective-C code is compiled into ARM binary code and executed directly.
Comparison between C# Features and Objective-C Classes
Let us start with an example program. In contrast to Objective-C, C# does not separate the class definition and the implementation. The compiler derives the metadata about the classes from the class implementation itself. You will also notice that you do not need to define each class in a separate file as in Objective-C.
In the example, the public signature of the class Person consists of just the property, age, and the constructor. The rest of the class implementation is opaque.
Instead of using the import statement, C# employs a using statement to refer to the metadata of other classes. The namespace declaration, shown at the top of the file, is used to both declare scope and organize the code. You can access classes in other namespaces by referring to a fully qualified name. See the reference to System.Console.WriteLine in the example above, where console is in the System namespace.
Objective-C uses a message passing syntax consisting of square brackets, and a dot-notation for accessing properties. C# uniformly uses the "." notation for referring to all methods, fields and properties.
In contrast to Objective-C, C# is a very strongly typed language. Types must be specified for variables as well as input/output parameters. Types are enforced strictly by the compiler. Objective-C uses weak typing for collection classes such as NSArray and NSDictionary. In the section on generics below, we will see how C# uses strong typing for collection classes.
The example above shows the strong typing for primitive types. Strong typing works similarly for all classes.
In contrast to the separate alloc and init statements of Objective-C, in C#, instance constructors are used to create and initialize instances. For example, p, an instance of the Person class, can be both constructed and initialized with a given birthdate, in a single statement.
Developers often need to decide about whether to implement a member as a property or a method. In this case, the design pattern is identical for Objective-C and C#. In general, the guidance is to use properties when accessing data, and to use methods when there is an action taken on the data.
As opposed to the Objective-C @property attribute, C# properties are declared by the explicit definition of a getter, a setter, or both. You can make the property read-only by providing just the getter, write-only by providing just the setter or read-write, by providing both.
Similarly to Objective-C, C# uses value parameters by default. While C# does not have pointers, it allows passing of parameters by reference by using the 'ref' modifier. Instead of pointers, parameters with ref can be used where you want to achieve side effects in a method. In some cases, reference parameters are more efficient, since they avoid data copying.
C# also provides parameters with an out modifier which denotes parameters that must be initialized by the called method before returning. This design pattern is often used to return the error in addition to the value of the function.
In Objective-C, access privilege can only be specified on variables. Methods which are present only in the .m file are private. On the other hand, C# allows access privileges on fields (e.g., birthDate), properties (e.g., age) and methods (e.g., ageOn). It uses public, private and protected as modifiers to denote three different levels of access privileges.
In the above example, the compiler will error out on p.birthDate since that variable is private and therefore is not accessible from the Program class. Similarly, the method ageOn is also private and inaccessible from the Program class.
Methods with multiple parameters
Both Objective-C and C# support methods with multiple parameters. In Objective-C method parameters are positional and named, i.e., the names of formal parameters are used while passing actual parameters. The name of the method is comprised of everything to the left of the colon (":"), for example, the name of the Objective-C method below is addEmployee:name:age:. While C# traditionally used positional and unnamed parameters, the latest version of C# has also introduced named parameters. The following example shows the comparative syntax for Objective-C and C#.
Objective-C does not support method overloading. While it does not allow exactly the same method signature with different parameter types, the following design pattern is commonly used in Objetive-C programs:
- (void)insert:(myClass *)obj atIndex:(NSInteger)index
- (void)insert:(myClass *)obj beforeObj:(myClass *)obj
[mylist insert:obj1 atIndex:4];
[mylist insert:obj2 beforeObj:obj1];
As we saw earlier, the names of these two methods are different and are "insert:atIndex" and "insert:beforeObj" respectively.
On the other hand, C# explicitly supports method overloading. Using information about the parameter types, C# disambiguates between methods with the same name.
void insert(myClass obj, int index);
void insert(myClass obj, myClass before);
The method insert may be called with both signatures:
Now that we have examined some of the basic class concepts in C#, let us look at another example:
Like Objective-C, C# also uses a single inheritance mechanism. Inheritance is specified by listing the parent class after the name of the class as shown below. In the above example, the class Rectangle inherits from the class Shape, whereas the class Square inherits from the class Rectangle.
In C#, the constructor of the base class is automatically invoked when constructing an instance of a derived class. However, a derived class can invoke a specific constructor of the base class if needed as shown in the constructor of the Square class.
In contrast to Objective-C, a C# derived class may not override a method by just redefining it. The class must use the keyword "override" in its method definition.
Objective-C provides protected variables, but methods cannot be protected. In C#, access to fields, properties and methods can also be controlled using the protected modifier. You can implement protected variables in C# by using the protected access modifier, as shown below:
Instance vs Class Level Access
While Objective-C and C# use different syntactic notation for
static methods or variables, they behave the same way. C# uses a
'static' modifier to denote class level methods, fields or
properties. Everything else is at an instance level. In the above
example, counter is a class level variable.
Abstract classes, are classes that cannot be instantiated. While Objective-C does not provide a syntax for abstract classes, many programmers use them by returning NULL from the abstract class init method. The class Shape, defined above in C#, is an abstract class and requires that both Area and the method contains must be overridden in any derived classes.
Objective-C protocols and C# interfaces are similar. In the example below, IThreeDShape defines an interface that is implemented by the Cube class.
Polymorphism works the same way in both Objective-C and C#. A C# derived class can be passed as a parameter to a method that expects a base class. Similarly, a class that implements a particular interface can also be passed as a parameter to the method. This is shown in the example below, where an object of the class Cube is passed as a parameter, where the method expects an object of the class IThreeDShape.
In contrast to the C-based structs used in Objective-C, C# structs are closer to classes. C# structs can have constructors, methods and properties as well as access modifiers. However, the primary difference between a struct and a class is that a struct is a value type, versus a class, which is a reference type.
Object Lifecycle - Creation and Deletion of Objects
Memory management is very different in Objective-C and C#. In contrast to Objective-C, C# performs automatic memory management. As we saw earlier, developers do not allocate memory, but use the "new" operator to create objects on the heap and initialize them. Equally important, in C#, the developer is not responsible for tracking memory usage or knowing when to free memory. When the object is no longer accessed by the code, the object is eligible for garbage collection. Periodically, the .NET CLR garbage collector frees up the memory for such objects.
In rare circumstances, developers may need to perform cleanup at the time the object is destroyed. C# allows the use of destructors, but in practice this is rare.
Type Checking v/s Reflection
In Objective-C, you can check the type of the class or determine if an object supports a particular method and invoke the method on that object. In C#, reflection is a versatile feature. You can use reflection to get the type information from an existing object, dynamically create an instance of a type, bind the type to an existing object, invoke its methods or access its fields and properties.
The following table explains the mapping between dynamic type checking in Objective-C and the corresponding C# reflection features.
Exception handling is similar in C# and Objective-C. You use a try-catch block to handle exceptions. Additionally, you can either catch specific exceptions or use a catch-all statement. This is similar to @try, @catch and @finally statements in Objective-C.
Key class libraries compared
C# provides a very comprehensive string class, which gives you all the features that you are familiar with in the NSString class.
C# provides a generic dictionary class that provides the functionality of NSMutableDictionary. It allows addition, lookup and removal of objects in the dictionary. Since it uses generics, it also utilizes strong typing.
New features of C#
Generics introduce the notion of type parameters, that make it possible to design classes that are type safe, even though the actual type is deferred till the object instantiation. For example, here is how you define a generic stack:
The Stack<T> uses T as a type parameter allowing you to instantiate a stack of any type, e.g. Stack<int> or Stack<string> and use them in a type safe manner.
Use of generics is closest to the use of id in Objective-C collection classes such as NSDictionary.
Operator overloading permits a user defined implementation of user-defined operators for user-defined classes. Consider the following example of a Complex number struct. Operator overloading allows you to define a '+' operation using a natural syntax.
Objective-C developers often use delegation for notification as to when an asynchronous operation is completed. In C#, delegates are similar to function pointers in C or Objective-C. In this design pattern, a class delegates another class, not known at compile time, to complete its action.
Let us look at the above example, where StringDelegate is defined as a function that takes a string as a parameter and returns void. Three different delegates, writer, logger and multiLogger, are constructed by passing in methods that have the same signature as the StringDelegate declaration. This can be contrasted with Objective-C delegates, which are usually defined using protocol declaration.
Calling Writer invokes the writeString method of ConsoleLogger to print the message to the console. On the other hand, calling Logger invokes the logString method of FileLogger to log the message to the file. As you can see, delegates achieve indirection while providing type safety. Delegates may be concatenated, as shown by MultiLogger, which logs the message to both loggers.
Events in C# are useful in the pub-sub (publisher and subscriber) design pattern. Events are a very powerful design pattern for asynchronous programming. An object can publish a set of events that subscribers in turn subscribe to. When the publisher raises the event, all subscribers are notified. The publisher raises the event without knowing who is listening to the events. Events are built using delegates, as shown below.
C# is a strongly typed, object oriented programming language that uses static binding. Many Objective-C concepts map closely to corresponding C# concepts. This chapter is a quick introduction to how C# concepts map to those of Objective-C. It provides a starting point for Objective-C users and points to additional resources. Knowledge of object oriented programming, and Objective-C experience, will provide a strong foundation to enable you to master C# quickly.