C#
The C# programming language (pronounced "C sharp") was introduced with the .NET Framework. It represents a milestone in the area of programming language development. Even though the genesis of the new C# language is in existing programming languages such as Java and C++, it represents the most innovative, modern, and evenin most areasthe preferred .NET programming language. C# was introduced to combine the key values of Visual Basic and C++. Whereas Visual Basic had ease of use and high developer productivity, C++ represented the ultimate flexibility and control. C# merges the two; it is relatively simpler than C++ (no pointers, templates, and so on), and it has all the nice object-oriented features of C++ and the ease of use of Visual Basic. No more specific memory allocation is required, as everything is "garbage collected" by the common runtime. In various ways, C# is also similar to the Java programming language, which has gained wide developer support as well. However, whereas Java is intended to be a platform-neutral programming language compiling into byte code and then executed on a virtual machine, C# programs are compiled (like all .NET programming languages) into MSIL (Microsoft Intermediate Language) and, like all applications, are ultimately converted into machine code before execution.
C# Programming Language: The Standard
A key aspect of the .NET platform is that it is based on top of existing and new standards. For instance, the C# programming language has been approved as an ISO standard (23270). More details about the standardization initiative and the standard itself are available at http://msdn.microsoft.com/net/ecma/.
C# follows a code-focused model, targeted for developers who like the simplicity of a modern programming language but typically prefer to write programs by hand instead of generating them with wizards. This enables easier reuse because the code is relatively easier to understand by other developers using it. Key highlights of the C# programming language are the following:
Ease of Visual Basic with the power of most C++ features
Similar programming language syntax for C++ and Java developers
Support for all CLR data types
Pass by reference and value for parameters
Operator overloading (not found in Java)
Capability to run clearly marked "unsafe" code
XML-based documentation, using special comments
Integration with Visual Studio .NET for rapid development
Hello World
In this section, you'll take a look at a Hello World C# program. Each C# application is composed of a class. If it is an executable application, one of the classes available should have a static Main() method that serves as the entry point. (The compiler would warn if Main was not declared or improperly declared.) The Main method is overloaded and can have a String array passed to it as well for any command-line parameters.
using System; namespace hks { public class HelloWorld { public static void Main() { Console.WriteLine("Hello World in C#"); } } }
C# classes are stored in .cs files. After you have saved the preceding program in a file, let's say Hello World. You can compile the program into a .NET executable. You will need to include the .NET Framework SDK's bin folder in your PATH variable. If you have installed Visual Studio .NET, you have a shortcut under Visual Studio .NET Tools called Visual Studio .NET 2003 Command Prompt. This shortcut initializes all the environment variables and provides access to the command-line compilers as well.
csc HelloWorld.cs
Now enter HelloWorld.exe to run the application, and you should see "Hello World in C#" echoed on the screen.
Comments
C# provides a couple of ways to introduce comments in a program; the two most popular are the traditional single-line comments (//) and the multiline comments (/* */). In addition, C# provides XML-based comments that can be used to create XML documentation from a set of code files. These XML files can then be processed with an XSLT (XML Stylesheet Language) to convert into online HTML documentation, and so on.
using System; namespace hks { /// <summary> /// A Simple Class /// </summary> public class Comments { public static void Main() { // A Simple comment /* A multi line comment */ Console.WriteLine("Hello World in C#"); } } }
Data Types
Table 3.1 describes how the C# types are mapped into the corresponding .NET Framework types. In a true sense, the C# keywords are really a compact representation for the .NET type.
Table 3.1 C# Data Types
C# Type |
Corresponding .NET Framework Type |
Bool |
System.Boolean |
byte, sbyte |
System.Byte, System.SByte |
Char |
System.Char |
decimal, double, single |
System.Decimal, System.Double, System.Single |
short, ushort, int, uint, long, ulong |
System.Int16, System.UInt16, System.Int32, System.UInt32, System.Int64, System.UInt64 |
Object |
System.Object |
String |
System.String |
Enumerations
C# provides the enumerations programming construct, which provides a human-readable form of a series of related constant values.
using System; namespace hks { public class UseEnumerations { enum CreditCard { Visa = 0, MasterCard = 1, AmericanExpress = 2, Discover = 3 } public static void Main() { CreditCard mycard = CreditCard.Discover; Console.WriteLine(mycard); Console.WriteLine((int) mycard); } } }
Arrays
Arrays provide developers with a structure for storing a collection of values. Apart from arrays, the .NET Framework provides a series of Collections constructs, including Hash Tables and ArrayList, which provide capabilities such as dynamic sizing. You will look at some of those constructs in the next chapter. Arrays can be processed by a foreach construct.
using System; namespace hks { public class UseArrays { public static void Main() { String[] days_of_week = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; foreach (string day in days_of_week) { Console.WriteLine(day); } } } }
Variables and Constants
Simple value types can be assigned using the variable = value construct, whereas reference types are required to use the new keyword for creating a new instance.
using System; namespace hks { public class UseVariables { public static void Main() { const string HELLO_WORLD = "Hello World"; string message = HELLO_WORLD+ " in C#"; MyClass mc = new MyClass(message); mc.Print(); } } public class MyClass { private String message; public MyClass(String message) { this.message = message; } public void Print() { Console.WriteLine(message); } } }
Expressions
Expressions in C# are very similar to those provided by Java and C++ programming languages.
using System; namespace hks { public class UseExpressions { public static void Main() { int a = 10; int b = 10; int result = a * b; bool check = (a == b); Console.WriteLine(result); Console.WriteLine(check); } } }
Statements
As expected, the C# programming language includes several procedural programming constructs, including if-else, for loop, while loop, switch statements, and so on.
using System; namespace hks { public class UseStatements { public static void Main() { string[] message = {"Hello", "World", "in", "C#"}; foreach (string msg in message) { Console.Write(msg+" "); } Console.WriteLine(""); int a = 10; int b = 20; if (a < b) { Console.WriteLine("a<b"); } else { Console.WriteLine("a>=b"); } } } }
Structures
Structures are simply an aggregation of value types and are allocated on the stack and not on the heap. Structures are useful for passing a logical and related set of data values. Structures don't support inheritance but can implement interfaces. For instance, the following program would print Hitesh.Seth followed by John.Doe and illustrates that structures are not reference types.
using System; namespace hks { public class UseStructures { public static void Main() { Person hs = new Person("Hitesh","Seth"); Person jd = hs; jd.FirstName = "John"; jd.LastName = "Doe"; Console.WriteLine(hs.FirstName+"."+hs.LastName); Console.WriteLine(jd.FirstName+"."+jd.LastName); } } public struct Person { public string FirstName, LastName; public Person(string FirstName, string LastName) { this.FirstName = FirstName; this.LastName = LastName; } } }
Classes
Classes, on the other hand, are reference types and hence are allocated on the heap. Classes provide object-oriented constructs such as encapsulation, polymorphism, and inheritance. For instance, the following program would print John.Doe twice, illustrating that objects are reference types, allocated on the heap.
using System; namespace hks { public class UseClasses { public static void Main() { Person hs = new Person("Hitesh","Seth"); Person jd = hs; jd.FirstName = "John"; jd.LastName = "Doe"; Console.WriteLine(hs.GetFullName()); Console.WriteLine(jd.GetFullName()); } } public class Person { private string sFirstName, sLastName; public Person(string FirstName, string LastName) { this.sFirstName = FirstName; this.sLastName = LastName; } public string FirstName { get { return sFirstName; } set { sFirstName = value; } } public string LastName { get { return sLastName; } set { sLastName = value; } } public String GetFullName() { return this.FirstName + "."+ this.LastName; } } }
Inheritance
Classes provide inheritance capability, which allows the derived class to inherit the functionality of a base class and potentially override some of the methods. A class definition consists of constructors and destructors, members, methods, properties, and events. (You will learn more about events later in this section.) Unlike the Java programming language, in C# all methods that are overridden must be marked as virtual in the base class. The is operator provides runtime validation if an object is of a particular type. For instance, the following program will return that a FullPerson object is always a Person.
using System; namespace hks { public class UseInheritance { public static void Main() { FullPerson hs = new FullPerson("Hitesh","K","Seth"); Console.WriteLine(hs.GetFullName()); Object oHs = hs; if (oHs is Person) { Console.WriteLine("I am still a Person"); } } } public class Person { public string FirstName, LastName; public Person(string FirstName, string LastName) { this.FirstName = FirstName; this.LastName = LastName; } public virtual string GetFullName() { return this.FirstName + "." + this.LastName; } } public class FullPerson : Person { public string MiddleInitial; public FullPerson(string FirstName, string MiddleInitial, string LastName) : base(FirstName,LastName) { this.MiddleInitial = MiddleInitial; } public override string GetFullName() { return this.FirstName + "." + this.MiddleInitial + "." + this.LastName; } } }
Classes can also be marked as either abstract (Listing 3.1), which means they have to be subclassed for any instances to be created, or sealed, which does not allow any subclassing.
Listing 3.1 Using Abstract Classes (C#)
using System; namespace hks { public class UseAbstractClasses { public static void Main() { Person hs = new Person("Hitesh","Seth"); Console.WriteLine(hs.GetFullName()); } } abstract public class Abstract { protected string FirstName, LastName; public Abstract(string FirstName, string LastName) { this.FirstName = FirstName; this.LastName = LastName; } abstract public string GetFullName(); } public class Person : Abstract { public Person(string FirstName, string LastName) : base(FirstName, LastName) { } public override string GetFullName() { return FirstName+"."+LastName; } } }
Interfaces
C# provides the concept of interfaces. Interfaces really represent a signature of what needs to be implemented by a derived class. C# supports multiple inheritances of interfaces (Listing 3.2).
Listing 3.2 Using Interfaces (C#)
using System; namespace hks { public class UseInterfaces { public static void Main() { Person hs = new Person(); hs.Name = "Hitesh Seth"; hs.Address = "1 Executive Drive, City, NJ 08520"; Console.WriteLine(hs.GetName()); Console.WriteLine(hs.GetAddress()); } } public interface IName { string GetName(); } public interface IAddress { string GetAddress(); } public class Person : IName, IAddress { private string name, address; public Person() { } public string Name { set { name = value; } } public string Address { set { address = value; } } public string GetName() { return name; } public string GetAddress() { return address; } } }
Exception Handling
C# provides robust exception handling capabilities. For instance, the program that follows catches the exception at runtime and allows messages to be displayed to the end user without requiring an intermediate exit.
using System; namespace hks { public class UseExceptions { public static void Main() { try { int a = 10; int b = 10; int c = a/(a-b); } catch (Exception ex) { Console.WriteLine("Exception Caught"); Console.WriteLine(ex.Message); } } } }
Custom exceptions, which contain more information related to the underlying application, can also be created. Custom exceptions derive from the System.Exception class. For instance, Listing 3.3 shows the custom exception TooBigDiscountException being declared and thrown by the constructor.
Listing 3.3 Creating Custom Exceptions (C#)
using System; namespace hks { public class UseCustomExceptions { public static void Main() { try { Discount big_discount = new Discount(56); } catch (TooBigDiscountException ex) { Console.WriteLine("Exception Caught"); Console.WriteLine(ex.Message); } } } public class Discount { private int percent; public Discount(int percent) { this.percent = percent; if (percent > 50) throw new TooBigDiscountException("Discount > 50%"); } } public class TooBigDiscountException : Exception { public TooBigDiscountException(String msg) : base (msg) { } } }
Delegates
Delegates give C# programmers the capability of function pointers, basically passing a function as a parameter. For instance, Listing 3.4 shows two delegates to be created and then invoked.
Listing 3.4 Using Delegates (C#)
using System; namespace hks { public class UseDelegates { public delegate void MyDelegate(string message); public static void Main() { String message = "Hello Delegates"; MyDelegate d1 = new MyDelegate(PrintOnce); MyDelegate d2 = new MyDelegate(PrintTwice); d1(message); d2(message); } public static void PrintOnce(String message) { Console.WriteLine(message); } public static void PrintTwice(String message) { Console.WriteLine("1."+message); Console.WriteLine("2."+message); } } }
Events
A typical use of delegates is in event handling. For instance, take a look at Listing 3.5. It defines a class called Button, which has a Delegate called EventHandler. Event handlers can be assigned for the event OnClick and allow the calling application to pass in the reference of the method Button_Click as the callback method to invoke after the button is clicked. In this program, the button clicking is done by explicitly invoking the Click method; in a real GUI application, the Click() method would be automatically invoked on user input. In Chapter 7, "Developing Windows Applications Using Windows Forms," you will see that the code is very similar to this application.
Listing 3.5 Using Events (C#)
using System; public class Events { public static void Main() { Button button = new Button(); button.OnClick+= new Button.EventHandler(Button_Click); button.Click(); } public static void Button_Click() { Console.WriteLine("Button Clicked"); } } public class Button { public delegate void EventHandler(); public event EventHandler OnClick; public void Click() { OnClick(); } }
That is really all this chapter covers on the C# programming language. Beyond what is covered in this chapter, a major part of this book uses C# as the primary programming language. For further explorations of the C# programming language, see Visual C# .NET 2003 Kick Start by Steve Holzner.