This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Sharp New Language: C# Offers the Power of C++ and Simplicity of Visual Basic
Going forward, C# is expected to be the best language from MicrosoftÂ® for writing COM+ and WindowsÂ®-based programs for enterprise computing. However, you won't have to migrate your existing C or C++ code. If you like the new features in C#â"and you probably willâ"you can migrate your mindset to C#. Let's face itâ"C++ is a powerful language, but it isn't always a walk in the park. I've used both Visual Basic and C++ professionally, and after a while I was asking myself why I needed to implement every last destructor for every last C++ class. C'mon alreadyâ"you're a smart language. Visual C++Â® even has IntelliSenseÂ®. Clean up after me. If you like C and C++, but sometimes think like I do, C# is for you.
The main design goal of C# was simplicity rather than pure power. You do give up a little processing power, but you get cool stuff like type safety and automatic garbage collection in return. C# can make your code more stable and productive overall, meaning that you can more than make up that lost power in the long run. C# offers several key benefits for programmers:
SimplicityWhat's one of the most annoying things about working in C++? It's gotta be remembering when to use the -> pointer indicator, when to use the :: for a class member, and when to use the dot. And the compiler knows when you get it wrong, doesn't it? It even tells you that you got it wrong! If there's a reason for that beyond out-and out taunting, I fail to see it.
C# recognizes this irksome little fixture of the C++ programming life and simplifies it. In C#, everything is represented by a dot. Whether you're looking at members, classes, name-spaces, references, or what have you, you don't need to track which operator to use.
Okay, so what's the second most annoying thing about working in C and C++? It's figuring out exactly what type of data type to use. In C#, a Unicode character is no longer a wchar_t, it's a char. A 64-bit integer is a long, not an __int64. And a char is a char is a char. There's no more char, unsigned char, signed char, and wchar_t to track. I'll talk more about data types later in this article.
The third most annoying problem that you run across in C and C++ is integers being used as Booleans, causing assignment errors when you confuse = and ==. C# separates these two types, providing a separate bool type that solves this problem. A bool can be true or false, and can't be converted into other types. Similarly, an integer or object reference can't be tested to be true or falseâ"it must be compared to zero (or to null in the case of the reference). If you wrote code like this in C++:
ConsistencyC# unifies the type system by letting you view every type in the language as an object. Whether you're using a class, a struct, an array, or a primitive, you'll be able to treat it as an object. Objects are combined into namespaces, which allow you to access everything programmatically. This means that instead of putting includes in your file like this
Of course, you could get fancy. What if you want to reuse the HelloWorld program? Easyâ"put it into its own namespace! Just wrap it in a namespace and declare the classes as public if you want them accessible outside the particular namespace. (Note here that I've changed the name Main to the more suitable name SayHi.)
ModernityLike coding languages, the needs of programmers evolve over time. What was once revolutionary is now sort of, well, dated. Like that old Toyota Corolla on the neighbor's lawn, C and C++ provide reliable transportation, but lack some of the features that people look for when they kick the tires. This is one of the reasons many developers have tinkered with the Java language over the past few years.
C# goes back to the drawing board and emerges with several features that I longed for in C++. Garbage collection is one exampleâ"everything gets cleaned up when it's no longer referenced. However, garbage collection can have a price. It makes problems caused by certain risky behavior (using unsafe casts and stray pointers, for example) far harder to diagnose and potentially more devastating to a program. To compensate for this, C# implements type safety to ensure application stability. Of course, type safety also makes your code more readable, so others on your team can see what you've been up toâ"you take the bad with the good, I guess. I'll go into this later in this article.
C# has a richer intrinsic model for error handling than C++. Have you ever really gotten deep into a coworker's code? It's amazingâ"there are dozens of unchecked HRESULTs all over the place, and when a call fails, the program always ends up displaying an "Error: There was an error" message. C# improves on this situation by providing integral support for throw, tryï¿½catch, and tryï¿½finally as language elements. True, you could do this as a macro in C++, but now it's available right out of the box.
Part of a modern language is the ability to actually use it for something. It seems simple enough, but many languages completely ignore the needs for financial and time-based data types. They're too old economy or something. Borrowing from languages like SQL, C# implements built-in support for data types like decimal and string, and lets you implement new primitive types that are as efficient as the existing ones. I'll discuss some of the new support for data types and arrays later in the article.
You'll also be glad to see that C# takes a more modern approach to debugging. The traditional way to write a debuggable program in C++ was to sprinkle it with #ifdefs and indicate that large sections of code would only be executed during the debugging process. You would end up with two implementationsâ"a debug build and a retail build, with some of the calls in the retail build going to functions that do nothing. C# offers the conditional keyword to control program flow based on defined tokens.
Remember the MSDNMag namespace? A single conditional statement can make the SayHi member a debug-only function.
Finally, C# is designed to be easy to parse, so vendors can create tools that allow source browsing and two-way code generation.
Object OrientedYeah, yeah. C++ is object oriented. Right. I've personally known people who have worked on multiple inheritance for a week, then retired out of frustration to North Carolina to clean hog lagoons. That's why C# ditches multiple inheritance in favor of native support for the COM+ virtual object system. Encapsulation, polymorphism, and inheritance are preserved without all the pain.
C# ditches the entire concept of global functions, variables, and constants. Instead, you can create static class members, making C# code easier to read and less prone to naming conflicts.
And speaking of naming conflicts, have you ever forgotten that you created a class member and redefined it later on in your code? By default, C# methods are nonvirtual, requiring an explicit virtual modifier. It's far harder to accidentally override a method, it's easier to provide correct versioning, and the vtable doesn't grow as quickly. Class members in C# can be defined as private, protected, public, or internal. You retain full control over their encapsulation.
Methods and operators can be overloaded in C#, using a syntax that's a lot easier than the one used by C++. However, you can't overload global operator functionsâ"the overloading is strictly local in scope. The overloading of method F below is an example of what this looks like:
Interfaces support multiple inheritance. Classes can privately implement internal interfaces through explicit member implementations, without the consumer ever knowing about it.
Type SafetyAlthough some power users would disagree with me, type safety promotes robust programs. Several features that promote proper code execution (and more robust programs) in Visual Basic have been included in C#. For example, all dynamically allocated objects and arrays are initialized to zero. Although C# doesn't automatically initialize local variables, the compiler will warn you if you use one before you initialize it. When you access an array, it is automatically range checked. Unlike C and C++, you can't overwrite unallocated memory.
In C# you can't create an invalid reference. All casts are required to be safe, and you can't cast between integer and reference types. Garbage collection in C# ensures that you don't leave references dangling around your code. Hand-in-hand with this feature is overflow checking. Arithmetic operations and conversions are not allowed if they overflow the target variable or object. Of course, there are some valid reasons to want a variable to overflow. If you do, you can explicitly disable the checking.
As I've mentioned, the data types supported in C# are somewhat different from what you might be used to in C++. For instance, the char type is 16 bits. Certain useful types, like decimal and string, are built in. Perhaps the biggest difference between C++ and C#, however, is the way C# handles arrays.
C# arrays are managed types, meaning that they hold references, not values, and they're garbage collected. You can declare arrays in several ways, including as multidimensional (rectangular) arrays and as arrays of arrays (jagged). Note in the following examples that the square brackets come after the type, not after the identifier as in some languages.
C# provides a foreach operator, which operates like its counterpart in Visual Basic, letting you loop through an array. Consider this snippet:
ScalabilityC and C++ require all sorts of often-incompatible header files before you can compile all but the simplest code. C# gets rid of these frequently aggravating headers by combining the declaration and definition of types. It also directly imports and emits COM+ metadata, making incremental compiles much easier.
When a project gets large enough, you might want to split up your code into smaller source files. C# doesn't have any restrictions about where your source files live or what they're named. When you compile a C# project, you can think of it as concatenating all the source files, then compiling them into one big file. You don't have to track which headers go where, or which routines belong in which source file. This also means that you can move, rename, split, or merge source files without breaking your compile.
Version SupportDLL Hell is a constant problem for users and programmers alike. MSDNÂ® Online has even dedicated a service specifically for users who need to track the different versions of system DLLs. There's nothing a programming language can do to keep a library author from messing around with a published API. However, C# was designed to make versioning far easier by retaining binary compatibility with existing derived classes. When you introduce a new member in a base class as one that exists in a derived class, it doesn't cause an error. However, the designer of the class must indicate whether the method is meant as an override or as a new method that just hides the similar inherited method.
As I've already mentioned, C# works with a namespace model. Classes and interfaces in class libraries must be defined in hierarchical namespaces instead of in a flat model. Applications can explicitly import a single member of a namespace, so there won't be any collisions when multiple namespaces contain similarly named members. When you declare a namespace, subsequent declarations are considered to be part of the same declaration space. Therefore, if your code looks like this
CompatibilityFour types of APIs are common on the Windows platform and C# supports all of them. The old-style C APIs have integrated support in C#. Applications can use the N/Direct features of COM+ to call C-style APIs. C# provides transparent access to standard COM and OLE Automation APIs and supports all data types through the COM+ runtime. Most importantly, C# supports the COM+ Common Language Subset specification. If you've exported any entities that aren't accessible from another language, the compiler can optionally flag the code. For instance, a class can't have two members runJob and runjob because a case-insensitive language would choke on the definitions.
When you call a DLL export, you need to declare the method, attach a sysimport attribute, and specify any custom marshaling and return value information that overrides the COM+ defaults. The following shows how to write a Hello World program that displays its message of cheer in a standard Windows message box.
If you want to import a COM class definition for use within your program, you must take two steps. First, you must create a class and use the comimport attribute to mark it as related to a specific GUID. The class you create can't have any base classes or interface lists, nor can it have any members.
FlexibilityIt's true that C# and COM+ create a managed, type-safe environment. However, it's also true that some real-world applications need to get to the native code levelâ"either for performance considerations or to use old-style, unmodernized APIs from other programs. I've discussed ways to use APIs and COM components from your C# program. C# lets you declare unsafe classes and methods that contain pointers, structs, and static arrays. These methods won't be type-safe, but they will execute within the managed space so you don't have to marshal boundaries between safe and unsafe code.
These unsafe features are integrated with the COM+ EE and code access security in COM+. This means that a developer can pin an object so that the garbage collector will pass over them when it's doing its work. (Sort of like a mezuzah for your code.) Unsafe code won't be executed outside a fully trusted environment. Programmers can even turn off garbage collection while an unsafe method is executing.
AvailabilityC# was announced in June and will be part of the upcoming Visual Studio .NET suite. A compiler is expected to be available later this year, in advance of the release of the next generation of Visual StudioÂ®.
For related articles see:
The Future of Visual Basic: Web Forms, Web Services, and Language Enhancements Slated for Next Generation
For background information see:
Object-Oriented Software Made Simple with COM+ Runtime Services
The COM+ Programming Model Makes it Easy to Write Components in Any Language
Joshua Trupin is the technical editor for MSDN Magazine. He has written numerous articles for MSJ and MIND, the predecessors to MSDN Magazine, as well as a book, Hoop Stats: The Basketball Abstract.
From the September 2000 issue of MSDN Magazine.