Visual C#. NET 2003 Unleashed
|
The Future of C#
Since the first pre-beta versions of the original 1.0 release of the .NET Framework were placed into the eager hands of waiting developers, Microsoft has been actively listening to feedback from the development community. Many times upgrades to developer tools are actually driven by marketing and other departments that have nothing to do with development. This isn't true for the next version of C#. Although countless new features are available in ASP.NET 2.0, Visual Studio .NET 2005, and the new Team System suite of Visual Studio projects, this chapter will focus on the improvements to the C# language itself. These improvements have been seamlessly integrated to the core of the language and are not simple add-ons. In some cases (as with Generics), changes have been made to the Common Language Runtime in order to accommodate these language features. The syntax and features of C# 1.1 are completely compatible with C# 2.0, so no existing syntax will ever break any C# 2.0 code. What follows is a quick tour of some of the exciting new features that are waiting for you in the next evolution of Visual C# .NET 2005. Generics
Generics provide a way for programmers to create classes that, at runtime, can be given types as parameters in order to more specifically control the behavior of the class. The best way to understand generics is to take a look at a programming task that many programmers have to accomplish with the current version of C# and then illustrate how that task is no longer necessary with C# 2.0 and generics. Listing 45.1 shows a class that inherits from CollectionBase to provide a strongly typed collection. Listing 45.1. An Implementation of a Strongly Typed Collection
using System; using System.Collections; using System.Collections.Specialized; namespace OldCollection { /// <summary> /// Summary description for Class1. /// </summary> public class OrderCollection: CollectionBase { public OrderCollection(): base() { } public Order this[int index] { get { return (Order)this.List[index]; } set { List[index] = value; } } public void Add( Order newOrder ) { List.Add( newOrder ); } public void IndexOf( Order order ) { List.IndexOf( order ); } public void Remove( Order order ) { List.Remove( order ); } } }
If you need to create a collection of orders, it takes a decent amount of extra code. Many times programmers decide to skip the strong typing and simply use the standard object-based collection classes because it's quicker and easier. With generics, all of that becomes unnecessary. You can now parameterize types. Microsoft has provided many generics-aware classes, such as Collection, that allow type arguments. Instead of writing an extra class just to get a collection of orders, you can now use the following syntax: Collection<Order> ordersCollection = new Collection<Order>();
To create a generic class, simply use the <> using System; using System.Collections; using System.Collections.Specialized; namespace GenericSample { Anywhere in the class definition that the type parameter T is used, C# considers it a type definition. So, at runtime, T myVariable might actually evaluate to Order myVariable or LineItem myVariable, depending on how the Generic class is instantiated. You can supply constraints on the Generic class, requiring that the type being used as a parameter provide a default constructor, implement certain interfaces, or even be derived from certain classes. This is just a preview of C# 2.0, so this chapter won't go into too much depth on the syntax for advanced generics. Visual C# .NET 2005 Unleashed (upcoming) will provide all the detail on generics that you might need. One thing to keep in mind is that generics are not the same as templates in C++ or generics in Java. Unlike other implementations that are compile-time substitutions, generics have been integrated completely into the Common Language Runtime. When the generic class is compiled by the JIT (Just-in-Time) compiler at runtime, the generic substitution is made. In other words, by using generics, the strong typing is available at compile time, so it is faster in some cases than providing your own strong typing at runtime, and it is completely IntelliSense-aware. The next version of the .NET Framework contains dozens of classes that have been built from the ground up with generics in mind. The following is a list of some of the collection-style classes that can be used with C# 2.0:
In addition to the preceding classes and many others, several interfaces also support generics. Some of the collection-related interfaces are as follows:
Anonymous Methods
Regardless of what kind of application you're creating, you have more than likely encountered a situation in which you need an extremely simple event handler. It can be tedious and unnecessarily complex to create this kind of event handler. To compensate for this, C# 2.0 provides support for anonymous (often referred to as inline) methods. An anonymous method is one that is defined within the context from which it is called. In standard code, to declare a delegate for a method and then invoke that delegate, the code looks something like this: class DelegateClass { delegate void MessageShowDelegate(string message); public void InvokeMethod() { MessageShowDelegate dg = new MessageShowDelegate( ShowMessage ); dg("Hello!"); } void ShowMessage( string msg ) { MessageBox.Show( msg ); } } Delegates are a crucial part of the event-handling plumbing of the .NET Framework. Instead of writing an extra method and creating an instance of a new delegate, you can write an anonymous method as the delegate, as shown in this C# 2.0 code: class DelegateClass { delegate void MessageShowDelegate(string message); public void InvokeMethod() { MessageShowDelegate dlg = delegate(string message) { MessageBox.Show(message); }; del(message); } }
The preceding code demonstrates that you can create a method on the fly using anonymous methods. It's simple code, but it has a variety of applications for making things extremely easy. Another added benefit of anonymous methods is that you often don't even have to declare the delegate type; its type can be inferred from the signature when it is invoked. Nullable Types at Last
Nullable types are a blessing that has been long awaited by database programmers everywhere. Programmers who spend a lot of their time interfacing with databases are often frustrated by the fact that the database allows scalar types (such as integer, double, float, bit, and so on) to contain a null value. Unlike the database, the current version of C# doesn't allow for nullable scalar types to match the features of the database. With C# 2.0, that is no longer true. Through the use of generics, developers can create an instance of the Nullable class parameterized with a value type. This provides the ability to create nullable integers, doubles, floats, and so forth. The following code shows how to create a nullable type: Nullable<int> x = new Nullable<int>(); x = 12; if ( x == null ) { // perform action } if (x.HasValue) { // perform some other action } Just like C# has shortcuts for System.String and System.Int32, it also has shortcuts for the nullable types. Instead of declaring Nullable<int>, you can simply declare a variable as int?, double?, and so forth. Adding the question mark to the end of the value type changes the declaration from a simple value type to a nullable value type. List Management with Iterators
If you've ever created a class that implemented an iterator, you are aware of how painful the process can be. It requires very certain code to be in place in a certain way, and is very prone to errors. Many people simply skip the process rather than deal with the headache of creating their own IEnumerable implementations. To create your own custom list of elements, not only do you have to implement IEnumerator, but you must also provide a class that implements IEnumerable. In C# 2.0, there is a new keyword called yield. This keyword enables you to easily define what information is to be yielded during enumeration of instances of the class. It dramatically simplifies the task of creating a class that implements the IEnumerable interface. The following code shows how to create an enumerable class that uses the new yield keyword: public class OrderCollection : IEnumerable<Order> { Order[] orders; public OrderCollection() { // populate the orders array } public IEnumerator<Order> GetEnumerator() { for (int i=0; i<orders.Length; i++) yield return orders[i]; } } }
With the preceding code, you can iterate through the collection of orders in a strongly typed fashion with no typecasting penalty and with a simple syntax: foreach (Order order in Orders) { // process order }
Partial Types
Partial types are part of the new design philosophy with the entire Visual Studio .NET 2005 product offering. The main goal behind partial types was to separate the code generated by visual designers from the code written by programmers. Today, that code is somewhat obscured from the developer by hiding it behind a collapsible IDE text region. With the new partial keyword, a C# 2.0 project can have multiple classes with the same name. The members of each partial definition become merged at compile time. Consider the following two partial classes: public partial class Car { private int mph; private bool AWD = false; public string GetColor() { return color.ToString(); } } public partial class Car { private Color color; public string GetAWD() { return AWD ? "All-Wheel Drive " : "Two-Wheel Drive"; } }
The interesting thing about the preceding two class definitions is that they refer to the same class. Each definition can have properties, fields, methods, and so on. What is new about this code is that either one of the partial class definitions can access members defined by the other. It is important to realize that even though the definitions are in different files and seemingly different classes, they contribute to the same class. There can even be more than two partial class definitions for the same class. The main benefit of partial classes will be immediately obvious to you when you start working with Visual Studio .NET 2005 and the new designers for Windows and Web Forms programming. Your code will no longer be cluttered, disorganized, and covered with auto-generated designer output. Static Classes
Static members of a class are those that are part of the class definition and not part of an individual instance of the class. Therefore, static members are retained in memory throughout the lifetime of the process in which the class resides. Such members are often used to store global data and configuration information in many different kinds of applications. Currently, you must create a class that looks something like the following class in order to prevent other programmers from creating an instance of the class: public class StaticClass { static int intMember = 0; private StaticClass() { // private-only constructor ... // throws exception when instantiated } public static int IntMember { get { return intMember; } set { intMember = value; } } }
Rather than have to rig up something like the preceding class with a private default constructor, C# 2.0 enables you to use the keyword static when defining classes. A static class is one that must define only static members. The compiler will enforce that rule, saving you the trouble. Static classes cannot be instantiated, and attempts to instantiate a static class will be flagged as errors at compile time. |
|