Sharp Shooter

Languages: C#

Technologies: .NET Framework | OOP



What s So Sharp about It?


By Mike Amundsen


There are so many great new things about ASP.NET that it s hard to decide what to dive into first. One of the biggest decisions you need to make when learning ASP.NET is which language to use when creating pages. For most programmers, it s a fairly easy choice. Most ASP developers are comfortable with VBScript. That means learning VB .NET is often the quickest way to get started with ASP.NET.


However, for those programmers who use JScript for ASP or who already know C++, J++, or just plain Java, VB .NET might not be the best way to go. For these folks, as well as the VB folks out there looking for adventure, C# offers a powerful, familiar, alternate language for building ASP.NET solutions.


At first glance, C# looks quite a bit like C++ with some JScript influences. C# offers the typical curly-brace and semi-colon terseness of C++ and also offers its object-orientation. Additionally, C# provides the great garbage-collection and type-safety features of the Java language family. But C# goes beyond all that to offer the great rapid-development feel of Visual Basic. This includes easy access to separate components (called assemblies in .NET) as well as rich database access and XML support. In fact, at the risk of offending the VB folks in the audience, C# just might offer the most friendly and effective programming environment for the Microsoft .NET platform.


At the same time, the introduction of C# to the Microsoft family of programming languages threatens to spark a family feud within the coding community. VB .NET folks rightly point out that their upgraded version of Visual Basic offers the same power and flexibility as does C#. And C++ users are quick to remind everyone that C++ is the only language that allows users to write for the Windows API directly or the .NET run time. Finally, JScript users happily advise all that, because of the high fidelity of JScript .NET to the current ECMA JScript, programmers can get up to speed very quickly with almost no changes to existing source code.


Why C#?

So the question is, What s so sharp about C#? Why go through the trouble of learning a new language if most of the features already exist in my current language of choice? Well, there are almost as many reasons for moving to C# as there are programmers. That s the real message here. The reasons to move to C# rest primarily on the preferences and interests of the programmers themselves. Thanks to the power and flexibility of the .NET run time, language selection no longer is based solely on the tasks you need to perform. Instead, your choice of language can be one of personal preference and interest. As the Microsoft folks like to say, language selection is now a lifestyle choice.


And where you have choice, you have opportunity. C# offers a great opportunity to stretch your mind. Take on new challenges and learn a new way to think about building desktop and Web applications. C# offers all the features of a rich, mature language as well as the latest in new programming paradigms. Developed by Anders Hejlsberg, the father of Turbo Pascal and Borland s Delphi languages, C# represents the latest in commercial programming language technology. Everyone who fancies himself or herself a professional programmer should spend time with C# if for no other reason than to gain a greater understanding of computer language theory and technology.


Along with the theoretical and technical advantages of learning a new language, C# is just plain fun to use. Designed to help programmers increase efficiency, C# provides excellent support for using components, accessing databases, and performing other tasks, such as XML messaging. Building robust applications in C# is just as fast and easy as in any high-level, component-oriented language, such as Visual Basic or Delphi.


C# has many exciting and compelling features. For readers who are new to C# and for readers who are already diving into this new programming environment, I ve collected a handful of the more noticeable features of the language. In the following sections, we ll explore these features a bit.


It s Object Oriented

One of C# s obvious features is that it is object oriented. In fact, C# is so object oriented that everything in C# is an object, even a simple string or numeric value. All C# classes derive from a base class called object. Even simple values are treated as objects within the language. This provides a powerful way to organize your programs and a very consistent way for the compiler to handle your code.


First, this object approach offers very powerful ways to handle data types and conversions within the language. For example, the code in FIGURE 1 shows how to create a simple object type and successfully fill it with various data types.


// source file:              SS01Obj01.cs

// command line compile:     csc SS01Obj01.cs

// command line execute:     SS01Obj01.exe


using System;


public class SS01Obj01 {

    static void Main() {

        object bucket;

        bucket = 13;


        bucket = "\nThis is a string";




FIGURE 1: Create an object type and fill it with various data types.


When you compile and run the code in FIGURE 1, you ll see two lines written to the screen (13 and This is a string). This works because C# knows all objects have a ToString method that can output the contents of the object in some way. This object orientation extends to literals as well. For example, FIGURE 2 shows how to execute methods of the base object without ever creating the actual object.


// source code file:         SS01Obj02.cs

// command line compile:     csc SS01Obj02.cs

// command line execute:     SS01Obj02.exe

using System;


public class SS01Obj02 {

    static void Main() {


        Console.Write("\nThis is an object!".ToUpper());



FIGURE 2: You can execute methods of the base object without ever creating the object.


FIGURE 2 shows that you can execute methods, such as ToUpper, directly on the literal string and shows you that you can use the ToString method on numeric literals. This works because C# treats the items as objects at compile time.


C# has many object-oriented features that deserve our attention. However, in the limited space we have here, there is room for just one more. FIGURE 3 shows you how you can create an abstract class (one that has no execution code) and then inherit from that class and implement the execution code.


// source code file:         SS01Obj03.cs

// command line compile:     csc SS01Obj03.cs

// command line execute:     SS01Obj03.exe


using System;


public class SS01Obj03 {

    static void Main() {

        impl01 myObj = new impl01();








abstract class abs01 {

    public abstract string getInfo();

    public abstract double

      computeValue(double v1, double v2);



class impl01 : abs01 {

    public override string  getInfo() {




    public override double

      computeValue(double v1, double v2) {




FIGURE 3: With this code, you can create an abstract class and then inherit from that class and implement the execution code.


C# offers a great object-oriented environment for building your applications. However, along with object orientation, you also need a programming language that offers safety against things such as runaway code, stray memory pointers, and stack overruns. Luckily, C# offers that, too.


C# Is Type-safe

Type-safe languages have features that work to prevent typical run-time problems, such as code that fails to return values, improper memory pointers that can cause your code to crash, invalid casting and conversions, infinite loops, and other errors. C# was designed to support this kind of type safety. This means it is much harder to create code that accesses invalid memory and code that causes stack overruns or type-conversion errors.


A typical problem is improperly casting values from one type to another. For example, the code in FIGURE 4 shows a common scenario: performing a math operation that can result in a data-type overflow.


// source code file:         SS01TS01.cs

// command line compile:     csc SS01TS01.cs

// command line execute:     SS01TS01.exe


using System;


public class SS01TS01 {

    static void Main() {

        short v1 = 3000;

        short v2 = 3000;

        short r1 = (v1+v2);

        Console.Write("Results: {0} + {1} = {2}",v1,v2,r1);



FIGURE 4: Performing a math operation that can result in a data-type overflow.


Even though the code above will result in a valid output, the compiler refuses to create the executable file and instead produces an error message. Because values v1 and v2 possibly could hold values that cause an overrun for r1, programmers must explicitly cast the results of the math operation into r1 as a short data type. FIGURE 5 shows code that compiles and runs properly.


// source code file:         SS01TS01a.cs

// command line compile:     csc SS01TS01a.cs

// command line execute:     SS01TS01a.exe


using System;


public class SS01TS01a {

    static void Main() {

        short v1 = 3000;

        short v2 = 3000;

        short r1 = (short)(v1+v2);

        Console.Write("Results: {0} + {1} = {2}",v1,v2,r1);



FIGURE 5: This code compiles and runs properly.


Now, even if the input values (v1 and v2) will result in an invalid (too large) value, the running program will not crash.


Another great example of type safety is how C# deals with function pointers. Instead of allowing programmers to discover memory address pointers and then use them at run time, C# offers delegates function prototypes that can be plugged in at run time. This provides the power of pointers without the problems. FIGURE 6 shows an example of using delegates to implement custom functionality at run time.


// source code file:         SS01TS02.cs

// command line compile:     csc SS01TS02.cs

// command line execute:     SS01TS02.exe


using System;


delegate void del01(string s);


class SS01TS02 {


    public static void Hello(string s) {

        Console.WriteLine("Hello, {0}!", s);



    public static void Goodbye(string s) {

         Console.WriteLine("Goodbye, {0}!", s);



    public static void Main() {

        del01 d1, d2, d3, d4;

        d1 = new del01(Hello);

        d2 = new del01(Goodbye);

        d3 = d1 + d2;

        d4 = d3 - d1;







FIGURE 6: Using delegates.


In FIGURE 6, a single delegate function (del01) is defined. This is like a pointer to an abstract function. There s no code definition, only the argument definition that indicates a single string input. Next, two complete functions (Hello and Goodbye) are defined. These have the same method signature (a single string input) and also have execution code that outputs an appropriate greeting. Finally, the main execution routine defines four delegate pointers (d1, d2, d3, d4) and then fills these delegate pointers with instances of the Hello and Goodbye methods. Notice that you can even add and remove instances using the + and operators. FIGURE 7 shows the output that results when executing this code.


Hello, Mike!

Goodbye, Mary!

Hello, Mark!

Goodbye, Mark!

Goodbye, Mazy!

FIGURE 7: Output results from the code in FIGURE 6.


You can see that executing d3 outputs both the Hello and Goodbye greetings, and d4 only emits the Goodbye message. Delegates are used throughout the .NET run time to implement event handlers, too. Delegates offer a great way to support pointer-like operations in a type-safe environment.



Another powerful aspect of the C# language is its use of a garbage-collection model for memory management. In the .NET run time, every time you use a new keyword, the run time allocates memory for the use of the object. Eventually, this memory must be cleared, and that s the job of the garbage-collection system. Unlike other languages that either require you to do your own collection work (as does C++) or do the collection immediately upon disposal of the object (as does Visual Basic 6.0), the .NET run time has a powerful garbage-collection engine that optimizes the process of memory management.


The greatest part about the optimized garbage collector (GC) is that you don t have to mess with it. That means no more reference counting for C++ folks and a much better-performing application for VB folks. However, if you re dead-set on messing with the GC, C# lets you do that, too. FIGURE 8 shows some code that uses the Collect and WaitForPendingFinalizers methods to force a garbage collection during the run of a short program.


// source code file:         SS01GC01.cs

// command line compile:     csc SS01GC01.cs

// command line execute:     SS01GC01.exe


using System;


public class SS01GC01 {

    public static void Main() {

      c1 a = new c1();

      a = null;

      Console.Write("**start forced collection\n");



      Console.Write("**end forced collection\n");

      c2 b = new c2();

      b = null;




class c1 {

   ~c1() {

      Console.WriteLine("destroy c1");




class c2 : c1 {

   ~c2() {

      Console.WriteLine("destroy c2");



FIGURE 8: Using the Collect and WaitForPendingFinalizers methods.


Notice there are two utility classes (c1 and c2) that have a destructor implemented (~c1 and ~c2). Notice also that c2 inherits from c1. Now, when you run the main routine, you get an instance of c1 and then release it. This does not force the run time to execute the destructor method and recover the memory. That will only be done if the memory is needed. However, by adding the call to the static methods on the Garbage Collector class, you can force the run time to run the destructor immediately. The other objects will not be destroyed until the program ends. FIGURE 9 shows the output of this short program.


**start forced collection

destroy c1

**end forced collection

destroy c2

destroy c1

FIGURE 9: Forcing the run time to execute the destructor immediately.


This optimized GC makes it very easy to build applications that use objects without worrying about reference counting and other details. And using objects, especially objects from other compiled components, is another key feature of C#.


It s Component-based

Now that you can see how easy it is to work with objects, you ll also see how simple it can be to create references to objects in other compiled components. Much like Visual Basic, the C# language is designed to make it easy to reference and use external components. No header files or type libraries are required. Everything your program needs to understand the classes, methods, and properties of external components are baked into the compiled .NET DLL (or assembly as it is called). All you need to do is add a reference to the assembly in your code, and you re all set.


FIGURE 10 shows a simple component DLL that displays the local server time. Once this component is compiled as a DLL, it can be placed in the BIN folder of any ASP.NET Web application for use in Web forms.


// source code file:         SS01Time.cs

// command line compile:     csc /target:library SS01Time.cs

// place the DLL in the BIN folder of the calling web app


using System;


namespace SharpShooter {

    public class SS01Time {

        public string getLocalTime() {





FIGURE 10: A component DLL that returns the local server time.


After compiling this DLL and placing it in the BIN folder of an existing Web application, you can create a page that uses the assembly and displays the local server time (see FIGURE 11).


<%@ page description="use external cs component" %>

<%@ import namespace="SharpShooter" %>


<script language="c#" runat="server">

void Page_Load(object sender, EventArgs args) {

    SS01Time thisTime = new SS01Time();

    showTime.Text = thisTime.getLocalTime();

    thisTime = null;







Check Local Time

   Local time is:

   <asp:Label id="showTime" runat="server"/>



FIGURE 11: This page uses an external component to display the local server time.


When you run this ASP.NET page, you ll see the local server time appear. That s how easy it is to use external components built using C#.



There you have it, a race through just a few cool features of the C# language. You get great support for building object-oriented code; powerful type safety that helps you build code that can reduce run-time errors; optimized garbage-collection service to maximize execution speed and minimize memory use; and quick, easy access to external components.


Sure, the other .NET languages offer similar features. Sure, these other oldsters can claim an existing, wide user base and general acceptance. But C# is the new kid in town. And sometimes it s just plain fun to be the first on your block with a new toy, isn t it?


In the next installment of Sharp Shooter: The irresistible class meets the immutable object, or taking advantage of the StringBuilder class.


The files associated with this article are available for download.


Mike Amundsen travels throughout the United States and Europe speaking about and teaching a wide range of topics, including .NET, the Internet, team development, and leadership. He also has written more than a dozen books. His most popular titles are SAMS Teach Yourself Database Programming with Visual Basic 6 in 21 Days, Third Edition with Curtis Smith (SAMS, 1998) and Using Visual InterDev 6 (QUE, 1998). With Paul Litwin, Mike just completed work on a new book covering Web development using Microsoft s .NET Framework, ASP.NET for Developers (SAMS). Readers may contact Mike at