Topic : Easy C#
Author : Joshua Trupin
Page : << Previous 3  Next >>
Go to page :


declare them they don't have a size. For this reason, you must create them after you declare them. Suppose you want an array of size 5. This code will do the trick:


int[] intArray = new int[5];

If you do this twice, it automatically reallocates the array. Therefore

int[] intArray;
intArray = new int[5];
intArray = new int[10];


results in an array called intArray, which has 10 members. Instantiating a rectangular array is similarly easy:


int[] intArray = new int[3,4];

However, instantiating a jagged array needs a bit more work. You might expect to say new int[3][4], but you really need to say:


int[][] intArray = new int[3][];
For (int a = 0; a < intArray.Length; a++) {
    intArray[a] = new intArray[4];
}


You can initialize a statement in the same line you create and instantiate it by using curly brackets:


int[] intArray = new int[5] {1, 2, 3, 4, 5};

You can do the same thing with a string-based array:


string[] strArray = new string[3] {"MSJ", "MIND","MSDNMag"};

If you mix brackets, you can initialize a multidimensional array:

int[,] intArray = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} };

You can also initialize a jagged array:


int[][] intArray = new int[][] {
new int[] {2,3,4}, new int[] {5,6,7}
};


If you leave out the new operator, you can even initialize an array with implicit dimensions:


int[] intArray = {1, 2, 3, 4, 5};

Arrays are considered objects in C#, and as such they are handled like objects, not like an addressable stream of bytes. Specifically, arrays are automatically garbage collected, so you don't need to destroy them when you're finished using them. Arrays are based on the C# class System.Array, so you can treat them conceptually like a collection object, using their Length property and looping through each item in the array. If you define intArray as shown earlier, the call intArray.Length

would return 5. The System.Array class also provides ways to copy, sort, and search arrays. C# provides a foreach operator, which operates like its counterpart in Visual Basic, letting you loop through an array. Consider this snippet:


int[] intArray = {2, 4, 6, 8, 10, -2, -3, -4, 8};
foreach (int i in intArray)
{
   System.Console.WriteLine(i);
}


This code will print each number in intArray on its own line of the system console. The System.Array class also provides a GetLength member function, so the preceding code could also be written like this (remember, arrays are zero-based in C#):


for (int i = 0; i < intArray.GetLength(); i++)
{
    System.Console.WriteLine(i);
}


Scalability



C 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 Support



DLL 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


namespace MSDNMag.Article
{
    class Author
    {
        ...
    }
}
namespace MSDNMag.Article
{
    class Topic
    {
        ...
    }
}


you could express the same code like so:


namespace MSDNMag.Article
{
    class Author
    {
        ...
    }

    class Topic
    {
        ...
    }
}


Compatibility



Four 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.


class HelloWorld
{
    [sysimport(dll = "user32.dll")]
    public static extern int MessageBoxA(int h, string m,
                                         string c, int type);

    public static int Main()
    {
        return MessageBoxA(0, "Hello World!", "Caption", 0);
    }
}


Each COM+ type maps to a default native data type, which COM+ uses to marshal values across a native API call. The C# string value maps to the LPSTR type by default, but it can be overridden with marshaling statements like so:


using System;
using System.Interop;

class HelloWorld
{
    [dllimport("user32.dll")]
    public static extern int MessageBoxW(
        int h,
        [marshal(UnmanagedType.LPWStr)] string m,
        [marshal(UnmanagedType.LPWStr)] string c,
        int type);

    public static int Main()
    {
        return MessageBoxW(0, "Hello World!", "Caption", 0);
    }
}


In addition to working with DLL exports, you can work with classic COM objects in several ways: create them with CoCreateInstance, query them for interfaces, and call methods on them. 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.


// declare FilgraphManager as a COM classic coclass
[comimport, guid("E436EBB3-524F-11CE-9F53-0020AF0BA770")]
class FilgraphManager
{
}


After the class is declared in your program, you can create a new instance of it with the new keyword (which is equivalent to the CoCreateInstance function).


class MainClass
{
    public static void Main()
    {
        FilgraphManager f = new FilgraphManager();
    }
}


You can query interfaces indirectly in C# by attempting to cast an object to a new interface. If the cast fails, it will throw a System.InvalidCastException. If it works, you'll have an object that represents that interface.


FilgraphManager graphManager = new FilgraphManager();
IMediaControl mc = (IMediaControl) graphManager;
mc.Run(); // If the cast succeeds, this line will work.

Flexibility


It'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

Page : << Previous 3  Next >>