Here is how our client looks in C#:
Listing 8. Client in C# (ClientCS.cs)
using System; using CompVC; using CompCS; using CompVB; // This "class" exists to house the application's entry-point class MainApp { // Static method "Main" is application's entry point public static void Main() { // Iterate over component's strings dump to console CompCS.StringComponent myCSStringComp = new CompCS.StringComponent(); Console.WriteLine("Strings from C# StringComponent"); for (int index = 0; index < myCSStringComp.Count; index++) { Console.WriteLine(myCSStringComp.GetString(index)); } // Iterate over component's strings dump to console CompVC.StringComponent myVCStringComp = new CompVC.StringComponent(); Console.WriteLine("\nStrings from VC StringComponent"); for (int index = 0; index < myVCStringComp.Count; index++) { Console.WriteLine(myVCStringComp.GetString(index)); } // Iterate over component's strings dump to console CompVB.StringComponent myVBStringComp = new CompVB.StringComponent(); Console.WriteLine("\nStrings from VB StringComponent"); for (int index = 0; index < myVBStringComp.Count; index++) { Console.WriteLine(myVBStringComp.GetString(index)); } } }
Unlike the Managed C++ example, we don't have to import the libraries at this point: Instead, we can specify them in the compile process. The advantage of specifying a library with the using
statement is that, by incorporating the namespace into the program, we can then reference types in the library without fully qualifying the type name. Since our particular example has the same type name (StringComponent
) in each of the components, we still have use the fully qualified name to remove any ambiguity when referring to the method (GetString
) and property (Count
), which are common to each component. C# also provides a mechanism called aliasing to address this problem: If you changed the using
statements to:
using VCStringComp = CompVC.StringComponent; using CSStringComp = CompCS.StringComponent; using VBStringComp = CompVB.StringComponent;
then you would not have to fully qualify the names.
The client code is virtually identical to the C++ example except for the scope resolution operators. Again, the code that calls the three string components is also the same except for specifying which library to use. As with the managed C++ example, the first statement in each of the three sections declares a new local variable of a type StringComponent
, initializes it, and calls its constructor::
CompCS.StringComponent myCSStringComp = new CompCS.StringComponent();
After writing out a string to the console to say we're entering this part of the program, the client then iterates over the members – up to the value of the Count
property – of appropriate string component:
for (int index = 0; index < myVCStringComp.Count; index++) { Console.WriteLine(myVCStringComp.GetString(index)); }
That's all that's required, and everything's repeated for the other two language components.
Building our new C# client is straightforward. Now that we're using components in our own relative "..\Bin" subdirectory, we need to explicitly include them using the /i
compilation switch:
csc /i:..\Bin\CompCS.dll;..\Bin\CompVB.dll; ..\Bin\CompVC.dll /out:..\Bin\ClientCS.exe ClientCS.cs
Also, since we're building a client program rather than a component that might be called from other programs, it is not necessary to use the /cls
+ switch.
Other than that, the process is the same as with the previous C# examples. Running the resulting program yields:
C:\Com20Dev\CompTest\Bin>clientcs Strings from C# StringComponent C# String 0 C# String 1 C# String 2 C# String 3 Strings from VC StringComponent VC String 0 VC String 1 VC String 2 VC String 3 Strings from VB StringComponent VB String 0 VB String 1 VB String 2 VB String 3