BUY THIS BOOK
Add to Cart

Print Book $24.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £17.50

What is this?

Looking to Reprint this content?


Mono: A Developer's Notebook
Mono: A Developer's Notebook By Edd Dumbill, Niel Bornstein
July 2004
Pages: 302

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Getting Mono Running
The labs in this chapter will guide you through obtaining, installing, and setting up Mono for Linux, Windows, and Mac OS X. The Mono system is comprised of the compiler, runtime, assemblies (code libraries), and documentation. In addition to these components, you will need a development environment and a build system. This chapter will cater to those needs too, whether using a graphical IDE or integrating Mono to fit snugly into your favorite and long-established editing environment.
Some of the labs in this chapter will only make complete sense after you've worked through Chapters 2 and 3, so feel free to come back and look around before you move on to Chapter 4.
Mono is distributed in three logical components: the Mono runtime and tools, the Mono API assemblies, and the Microsoft .NET compatibility API assemblies. Most of this book is about the Mono runtime, tools, and APIs, as described in the Preface. The exception is the coverage of ASP.NET, which allows you to develop web applications and web services.
Starting at the beginning, how do you get your hands on Mono?
This lab describes how to obtain and install Mono, and the major accompanying assemblies. The majority of the labs in this book can be completed using the packages installed as part of this lab. Where additional downloads are required, they will be noted in each lab concerned.
The best way to install Mono is to use the official packages. The Mono project has released precompiled packages for Linux (Red Hat, SuSE, and Fedora Core), Windows, and Mac OS X platforms. In addition, Linux distributions with their own download channels such as Debian or Gentoo have incorporated Mono into their usual repositories.
We don't control Mono's web site, so you may find things change slightly. Keep an eye on the online errata for this book for any corrections.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Install Mono
Mono is distributed in three logical components: the Mono runtime and tools, the Mono API assemblies, and the Microsoft .NET compatibility API assemblies. Most of this book is about the Mono runtime, tools, and APIs, as described in the Preface. The exception is the coverage of ASP.NET, which allows you to develop web applications and web services.
Starting at the beginning, how do you get your hands on Mono?
This lab describes how to obtain and install Mono, and the major accompanying assemblies. The majority of the labs in this book can be completed using the packages installed as part of this lab. Where additional downloads are required, they will be noted in each lab concerned.
The best way to install Mono is to use the official packages. The Mono project has released precompiled packages for Linux (Red Hat, SuSE, and Fedora Core), Windows, and Mac OS X platforms. In addition, Linux distributions with their own download channels such as Debian or Gentoo have incorporated Mono into their usual repositories.
We don't control Mono's web site, so you may find things change slightly. Keep an eye on the online errata for this book for any corrections.

Section 1.1.1.1: Linux

Packages for Linux systems with an x86 family CPU are available from the Mono download page, which you can access by clicking the "Download" link on the Mono home page, http://www.mono-project.com/. Users of RPM-based systems ( Red Hat, SuSE, and Fedora Core) should download the RPMs suitable for their Linux distribution.
To make life easier, Fedora Core users can set up a yum channel. To do this, add the following code to /etc/yum.conf, adjusting the URL to that given for Fedora from the Mono download page, and run yum
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Explore Mono
The addition to class assemblies and documentation, the Mono distribution contains a variety of tools for creating and executing Mono programs. This lab takes you through a guided tour of the most important tools.
Now you have Mono installed, what's in the box?
To get going with Mono, you must learn how to use the various command-line tools, especially mcs (the Mono C# compiler) and mono (the Mono virtual machine).

Section 1.2.1.1: mcs

mcs is the Mono C# compiler. You can compile, embed resources, and link Mono programs by using mcs. Try compiling the Hello World example from Section 2.1 with mcs Hello.cs. The result should be a file called Hello.exe.
mcs doesn't compile programs into directly executable code; rather, it compiles into an intermediate bytecode called Common Intermediate Language (CIL).

Section 1.2.1.2: mono

The mono command executes a compiled Mono program in the virtual machine. mono uses a just-in-time compiler (JIT) to translate the compiled CIL bytecode to machine code for execution. The Hello.exe program can be run with mono Hello.exe.
Find out which version of Mono is installed by running mono —version. The output will look something like this:
Mono JIT compiler version 0.91, (C) 2002-2004 Novell, Inc
and Contributors. www.go-mono.com
        TLS:           NPTL
        GC:            Included Boehm (with typed GC)
        SIGSEGV      : altstack
        Globalization: ICU
Include this version information if you need to ask questions in any of the forums listed in Section 1.5.

Section 1.2.1.3: mint

Not every platform on which Mono runs has the JIT compiler implemented yet. A slower alternative to
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Run the MonoDevelop IDE
MonoDevelop is a port of the SharpDevelop .NET integrated development environment (IDE) to Linux, using the Gtk# user interface toolkit. Both MonoDevelop and SharpDevelop are free, open source applications.
Real men may use vi, but productive ones use an IDE.
As you work through the labs in this book, you'll need a development environment to work in. While Section 1.4 provides hints on how to integrate Mono with an existing setup, this lab shows you how to get up and running with MonoDevelop. For the Mono 1.0 release, MonoDevelop is supported only on Linux, although some members of the Mono community have made it run on Mac OS X. See the "What about" section near the end of this lab for IDE solutions for Windows and Mac OS X.
MonoDevelop provides modern programming aids common to most IDEs, such as class browsing, integrated API documentation, build system, code completion, and support for multiple filetypes. Even if you're a hardened command-line and text editor geek, it's worth giving MonoDevelop a try. The integrated documentation is a great aid in navigating the many new APIs that Mono makes available.
Source code and precompiled packages of MonoDevelop can be obtained from the project web site at http://www.monodevelop.com. If possible, use precompiled packages for installation, because the number of prerequisites required to compile MonoDevelop is a little daunting. Users of the Debian (unstable) or Gentoo Linux distributions should be able to locate a monodevelop package using apt-get or emerge.
Before taking a tour of MonoDevelop's features, here's a word about how it organizes source code. MonoDevelop solutions may contain one or more projects. A project contains one or more files, which are compiled and linked to create a target assembly. For small undertakings, such as those in this book, a solution is likely to contain only one project.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Fit Mono into Your World
Everybody has their preferred development environment, whether it's just a text editor or a full-blown IDE. While Mono has a great IDE in the form of MonoDevelop, there may be many reasons for continuing with your current environment.
Development environments are a near-religious issue. Mono won't make you abandon your favorite tools.
This lab shows how Mono can be integrated with some of the more common tools used by Linux and Java developers.
If you are an old-school geek, you probably prefer to write your code with a text editor such as Emacs or Vim. Support for editing in C# ships as part of Vim 6.2, which can be found at http://www.vim.org/. Emacs users should install Brad Merrill's C# mode, available from http://www.cybercom.net/~zbrad/DotNet/Emacs/.
Brad Merrill has worked on .NET at Microsoft since 1999, so he's had plenty of time to refine his Emacs C# mode!
Unix geeks will also be familiar with using make to build their programs. It's simple to use make to control the building of Mono programs. The most obvious difference from C and C++ is that Mono doesn't need intermediate object files, so all the source files must be given to the compiler at once. Example 1-1 shows an example makefile that can be used as a starting point. The accompanying source files used by this makefile are available from the book's web site.
Example 1-1. Using make with Mono: 04-integrate/Makefile
# 01-tooling/04-integrate
MCS = mcs

ifdef DEBUG
MCSFLAGS = -debug
endif

.PHONY: clean all

all: SimpleMain.exe Main.exe FatMain.exe Library1.dll

# default way to make executables
%.exe: %.cs
  $(MCS) $(MCSFLAGS) -target:exe -out:$@ $(filter %.cs,$^) \
    $(foreach dl,$(filter %.dll,$^),$(addprefix -r:,$(dl)))

# default way to make libraries
%.dll: %.cs
  $(MCS) $(MCSFLAGS) -target:library -out:$@ $(filter %.cs,$^) \
    $(foreach dl,$(filter %.dll,$^),$(addprefix -r:,$(dl)))


# SimpleMain.exe is automatically built from its sole
# source file, SimpleMain.cs

# Main.exe has two source files and links with Library1.dll
Main.exe: Main.cs Sprockets.cs Library1.dll

# Library1.dll is automatically built from its sole 
# source file, Library1.cs

# FatMain.exe has some resources, and links against Library1.dll
# define them in variables, let make do the walking
FATMAIN_RESOURCES = monkey.png readme.txt
FATMAIN_SOURCES = Main.cs Sprockets.cs Widgets.cs
FATMAIN_LIBS = Library1.dll

FatMain.exe: $(FATMAIN_SOURCES) $(FATMAIN_RESOURCES) $(FATMAIN_LIBS)
  $(MCS) $(MCSFLAGS) -target:exe -out:$@ \
    $(foreach res,$(FATMAIN_RESOURCES), \
      $(addprefix -resource:,$(res))) \
    $(foreach dl,$(FATMAIN_LIBS),$(addprefix -r:,$(dl))) \
    $(FATMAIN_SOURCES)

clean:
  rm -f *.exe *.dll
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Join the Mono Community
One of the few disadvantages of this book is that, once printed, it can't change to cover the latest developments in the Mono world. Happily, help is at hand. Mono is a vibrant and evolving open source project, with a growing community of active developers and users. As such, there's a wide variety of online resources you can use to get news, help, and new tools for Mono.
Don't struggle on your own, there's a world of help out there!
This lab introduces the major Mono community resources and shows how to get the best out of them. As you continue to read through this book, familiarity with the Mono's online resources will help you in your exploration of Mono.
Before jumping into forums or mailing lists with questions, it's a good idea to make yourself as familiar as possible with Mono, its documentation, and recent developments. The first stopping-off point is the Web, where news, answers to common questions, and a variety of tutorials can be found.
Mono web site
Available at http://www.go-mono.com/, the Mono web site is the authoritative source for information on Mono. As well as a host of documentation, the Mono web site publishes the latest news about the project. The comprehensive list of frequently asked questions is a good resource for answering questions technical and commercial alike about Mono. The API documentation that ships with Monodoc is also available on the Web, by following the "Documentation" link.
MSDN
As the originators of .NET and the Common Language Runtime, Microsoft obviously has a lot to say on the topic. The Microsoft Developer Network, http://msdn.microsoft.com, contains a wealth of reference material and tutorials on using C#, and the APIs common to both Mono and the Microsoft .NET framework.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Getting Started with C#
C# (pronounced see-sharp) is a powerful, modern, object-oriented language whose syntax will be familiar for developers who have used C, C++, or Java. C# takes the simplicity of Java, with its automatic garbage collection, monolithic inheritance, and standard class library, and adds a number of advanced features, such as properties, delegates, and attributes.
This chapter will get you up to speed on C# syntax, the Common Language Infrastructure types, and some features unique to C#. To run the labs in this chapter, you must have a working Mono installation as described in Chapter 1.
This lab introduces some basic features of C# and the Framework Class Library (FCL). You'll see how to write and compile a simple "Hello, world!" program in C# and learn how C# is similar to other modern, object-oriented computer languages, as well as some of the keywords and language features unique to C#. Choosing from among the Choosing from among the panoply of Mono IDEs and installing your IDE of choice is discussed in Chapter 1.
Fire up your editor or IDE of choice, and create the file Hello.cs. Enter the following code (see Example 2-1) in your editor.
Example 2-1. 01-languagebasics/Hello.cs
// 02-csharp/01-languagebasics

public class HelloWorld {
  public static void Main (string [  ] args) {
    if (args.Length != 1) {
      System.Console.Error.WriteLine("You must tell me your name.");
      System.Environment.Exit(-1);
    }
    string name = args[0];
    System.Console.WriteLine ("Hello, {0}!", name);
  }
}
Now you have a simple C# source file. To compile it using Mono, type the following command at your command prompt:
You'll want to use your own name, unless you want to confuse your computer.
$ mcs Hello.cs
            
And to run it, type this command line:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Say "Hello" to the World
This lab introduces some basic features of C# and the Framework Class Library (FCL). You'll see how to write and compile a simple "Hello, world!" program in C# and learn how C# is similar to other modern, object-oriented computer languages, as well as some of the keywords and language features unique to C#. Choosing from among the Choosing from among the panoply of Mono IDEs and installing your IDE of choice is discussed in Chapter 1.
Fire up your editor or IDE of choice, and create the file Hello.cs. Enter the following code (see Example 2-1) in your editor.
Example 2-1. 01-languagebasics/Hello.cs
// 02-csharp/01-languagebasics

public class HelloWorld {
  public static void Main (string [  ] args) {
    if (args.Length != 1) {
      System.Console.Error.WriteLine("You must tell me your name.");
      System.Environment.Exit(-1);
    }
    string name = args[0];
    System.Console.WriteLine ("Hello, {0}!", name);
  }
}
Now you have a simple C# source file. To compile it using Mono, type the following command at your command prompt:
You'll want to use your own name, unless you want to confuse your computer.
$ mcs Hello.cs
            
And to run it, type this command line:
$ mono Hello.exe Niel
            
You'll see the following output on your screen:
Hello, Niel!
The class HelloWorld is small; it only contains the Main( ) method. Any class may have a Main( ) method; if more than one class passed to mcs.exe does have a Main( ) method, you can specify which one contains the method for a given executable at compile time with the -main:classname command-line switch.
Command-line arguments are passed to a C# program through the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Model the Behavior of Real-World Things
The C# language takes a number of its language features from C++. Java developers will already be familiar with the class and interface types. C# adds array and delegate types. In this lab you'll see how they work.
C# provides a rich set of reference types, including classes, interfaces, arrays, and delegates.
Example 2-3 shows the contents of a file called Beverage.cs, which demonstrates two of the four reference types. The Beverage class represents a beverage, about which certain properties can be queried. Every beverage is assumed to have a brand name, and every beverage is assumed to have a volume in fluid ounces. It is also assumed to contain some amount of caffeine-we're programmers, right?
The third reference type, interface, is discussed in this section. The fourth reference type, delegate, is complex enough that it merits its own lab. See Section 2.5.
Example 2-3. 02-reftypes/Beverage.cs
// 02-csharp/02-reftypes
using System;

public class Beverage {
  private string brand;
  private double volume;
  private double percentCaffeine;
  
  public Beverage(string brand, double volume, 
      double percentCaffeine) {
    this.brand = brand;
    this.volume = volume;
    this.percentCaffeine = percentCaffeine;
  }
  
  public string Brand {
    get {
      return brand;
    }
  }
  
  public double Volume {
    get {
      return volume;
    }
  }
  
  public double PercentCaffeine {
    get {
      return percentCaffeine;
    }
  }
  
  public override string ToString( ) {
    return Volume + " oz " + Brand + 
      " with " + PercentCaffeine + "% caffeine";
  }
}

public class BeverageTester {
  public static void Main(string [  ] args) {
    Beverage [  ] beverages = new Beverage [2];
    
    Beverage jolt = new Beverage("Jolt", 12.0, 0.25);
    beverages[0] = jolt;
    
    Beverage coke = new Beverage("Coca-Cola", 12.0, 0.125);
    beverages[1] = coke;
    
    foreach (Beverage beverage in beverages) {
      Console.WriteLine(beverage);
    }
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Avoid Overhead While Passing Data
In addition to the reference types in Section 2.2, C# also includes two value types. Value types can be used to model objects that are based mostly on data rather than behavior. In this lab, you'll see how to work with the struct and enum types.
Example 2-5 shows ValueTypes.cs, which demonstrates the use of the C# value types.
Example 2-5. 03-valuetypes/ValueTypes.cs
// 02-csharp/03-valuetypes
using System;

public enum Units {
  Ounces,
  Liters,
  Pints
}

public struct BeverageSize {
  private double volume;
  private Units units;
  
  public BeverageSize(double volume, Units units) {
    this.volume = volume;
    this.units = units;
  }
  
  public override string ToString( ) {
    return volume + " " + units;
  }
}

public class ValueTypesTester {
  public static void Main(string [  ] args) {
    BeverageSize size = new BeverageSize(12.0, Units.Ounces);
    Console.WriteLine(size);
  }
}
Compile and run Example 2-5 with the following commands to see the results:
$ mcs ValueTypes.cs
$ mono ValueTypes.exe
12 Ounces
ValueTypes.cs demonstrates how to define value types in C# using the enum and struct keywords. All value types, like all other CLI types, ultimately derive from System.Object, but they have an additional intermediate base class, System.ValueType. Value types differ from reference types in that a variable of value type contains the actual object data. Compare this to reference type variables, which, you will remember, contain a reference to the location of the object data. Additionally, value types are allocated on the stack, as opposed to reference types, which are allocated on the heap. Value types may not be null.
The first value type demonstrated in Example 2-5 is an enum. enum declares an enumeration type that derives from System.Enum. In addition to the C/C++-like behavior you would expect from an enumeration type, the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Handle Unexpected Errors
Many languages contain the concept of exceptions, a way to report errors and short-circuit processing. The C# System.Exception class and the try...catch...finally syntax are first-class members of the language, and are easy to understand and use. You can catch exceptions thrown by class libraries, rethrow them, clean up before moving on, and even declare and throw your own custom exceptions.
Exceptions help you handle those errors that inevitably come up when the unexpected and unwanted occurs.
Example 2-7 shows a class called FileFinder which handles some errors that might arise while opening a file.
Example 2-7. 04-exceptions/FileFinder.cs
// 02-csharp/04-exceptions
using System;
using System.IO;

public class FileFinder {
  
  public static void Main(string [  ] args) {
    string filename = null;
    try {
      // will throw IndexOutOfRangeException if the 
      // filename is not specified
      filename = args[0];

      // will throw FileNotFoundException if the file 
      // does not exist
      using(StreamReader reader = File.OpenText(filename)) {
        string contents = reader.ReadToEnd( );
      }
      
    } catch (IndexOutOfRangeException e) {
      Console.Error.WriteLine("No filename specified.");
      Environment.Exit(1);
      
    } catch (FileNotFoundException e) {
      Console.Error.WriteLine("File \"{0}\" does not exist.", 
        filename);
      Environment.Exit(2);
      
    } catch (Exception e) {
      Console.Error.WriteLine(e);
      Environment.Exit(3);
      
    } finally {
      Console.WriteLine("Done");
    }    
  }
}
Compile Example 2-7 with this command:
$ mcs FileFinder.cs
            
FileFinder.exe can be run with several different scenarios to produce different results. For example, run it without a parameter to catch the IndexOutOfRangeException and print an error message:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Define Function Pointers
Delegates fill the same role in C# that function pointers fill in C/C++, a role that is not filled at all in Java. They allow you to define a method signature but defer the assignment of an actual method until runtime. Delegates play a large role in the FCL and Mono class libraries, through the event mechanism, which we describe in this lab.
Sometimes you know you need to take action, but you'd rather let someone else decide exactly what action to take.
Example 2-9 shows the contents of the file WatchDirectory.cs. The class WatchDirectory demonstrates the general concepts of delegates and events, as well as giving a preview of one of the classes in the System.IO namespace, FileSystemWatcher.
Example 2-9. 05-delegates/WatchDirectory.cs
// 02-csharp/05-delegates
using System;
using System.IO;

public class WatchDirectory {

  private static void OnFileSystemEvent (object sender, 
      FileSystemEventArgs e) {
    Console.WriteLine("Something happened to {0}", e.Name);
  }
  
  private static void OnChanged (object sender, 
      FileSystemEventArgs e) {
    Console.WriteLine("{0} changed", e.Name);
  }
  
  private static void OnCreated (object sender, 
      FileSystemEventArgs e) {
    Console.WriteLine("{0} created", e.Name);
  }
  
  private static void OnDeleted (object sender, 
      FileSystemEventArgs e) {
    Console.WriteLine("{0} deleted", e.Name);
  }
  
  private static void OnRenamed (object sender, 
      RenamedEventArgs e) {
    Console.WriteLine("{0} renamed to {1}", e.OldName, e.Name);
  }
  
  public static void Main(string [  ] args) {
    string path = (string)args[0];
    FileSystemWatcher watcher = new FileSystemWatcher(path);
    watcher.Filter = "*";
    
    watcher.Changed += new FileSystemEventHandler(OnChanged);
    watcher.Created += new FileSystemEventHandler(OnCreated);
    watcher.Deleted += new FileSystemEventHandler(OnDeleted);
    watcher.Renamed += new RenamedEventHandler(OnRenamed);

    FileSystemEventHandler onFileSystemEvent = 
      new FileSystemEventHandler(OnFileSystemEvent);
    watcher.Changed += onFileSystemEvent;
    watcher.Created += onFileSystemEvent;
    watcher.Deleted += onFileSystemEvent;
    
    watcher.EnableRaisingEvents = true;
    Console.WriteLine("Enabled watcher on {0}; " +
      "hit return to terminate.", path);

    Console.ReadLine( );

    watcher.EnableRaisingEvents = false;

    watcher.Changed -= new FileSystemEventHandler(OnChanged);
    watcher.Created -= new FileSystemEventHandler(OnCreated);
    watcher.Deleted -= new FileSystemEventHandler(OnDeleted);
    watcher.Renamed -= new RenamedEventHandler(OnRenamed);

    watcher.Changed -= onFileSystemEvent;
    watcher.Created -= onFileSystemEvent;
    watcher.Deleted -= onFileSystemEvent;

    Console.WriteLine("done");
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Add Metadata to Your Types
Sometimes you need to specify additional information about a class or member, but until now most programming languages lacked built-in language constructs to express these details. Developers have been reduced to using interfaces as "markers" or hacking together special preprocessors to fill this need.
No more marker interfaces, no more preprocessor gunk in comments. Attributes do all that and much, much more!
C# addresses the need for custom declarative information with the concept of attributes. Attributes are classes derived from System.Attribute that may be placed on any C# language feature. Attributes add information about, and functionality to, the language features to which they are applied.
Attributes appear throughout the CLI. System.SerializableAttribute is one attribute that shows up quite often; it's used to mark a class which can be serialized, which is necessary for remoting and XML serialization (see Section 6.7). Example 2-10 shows a class which uses the SerializableAttribute attribute.
The naming standard for attribute types is to use Attribute as a suffix. However, when applying an attribute, the Attribute suffix may be omitted.
Example 2-10. 06-attributes/SerializableClass.cs
// 02-csharp/06-attributes
using System;

[Serializable]
public class SerializableClass {
  // ...
}
It's important to note that attributes are not normally used by the class or member that they are applied to. Instead, they are accessed via reflection at runtime by some other class that needs information about the object in question. SerializableAttribute is a perfect example; a class that is marked with the Serializable attribute does not implement any special methods or add any particular fields or properties. Instead, the System.Xml.Serialization.XmlSerializer
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Call External Libraries
One of the beauties of Mono is the fact that, as an open source project, it builds on other, existing, open source projects. Most of these other projects, such as the Boehm garbage collector and the IBM ICU library, are written in traditional unmanaged programming languages, such as C and C++, and are linked with the Mono runtime. Others, such as libxslt, are accessed through a technique known as Platform Invocation Services, or P/Invoke.
Don't discard all those open source C libraries just because you're using Mono!
For more information on curses, see Programming with curses by John Strang (O'Reilly).
You can use P/Invoke to invoke external libraries from your own C# code, too, as you'll see in this lab.
Let's begin with Example 2-12, which shows the file Curses.cs. The first class it defines, Curses, is a very rudimentary wrapper around the ncurses terminal-based user interface library.
Mac OS X users should replace const string Library="ncurses"; with const string Library="libncurses.dylib";
Example 2-12. 07-pinvoke/Curses.cs
// 02-csharp/07-pinvoke
using System;
using System.Runtime.InteropServices;

public class Curses {
  const string Library = "ncurses";
  
  [DllImport(Library)]
  private extern static IntPtr initscr( );
  
  [DllImport(Library)]
  private extern static int endwin( );

  [DllImport(Library)]
  private extern static int mvwprintw(IntPtr window, 
    int y, int x, string message);

  [DllImport(Library)]
  private extern static int refresh(IntPtr window);

  [DllImport(Library)]
  private extern static int wgetch(IntPtr window);

  private IntPtr window;
  
  public Curses( ) {
    window = initscr( );
  }
  
  ~Curses( ) {
    int result = endwin( );
  }

  public int Print(int x, int y, string message) {
    return mvwprintw(window, y, x, message);
  }
  
  public int Refresh( ) {
    return refresh(window);
  }
  
  public char GetChar( ) {
    return (char)wgetch(window);
  }
}

public class HelloCurses {
  public static void Main(string [  ] args) {
    Curses Curses = new Curses( );
    Curses.Print(10, 10, "Hello, curses!");
    Curses.Refresh( );
    char c = Curses.GetChar( );
    Curses = null;
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Package Related Classes with Assemblies
In the olden days of Windows programming, the term DLL hell was used to describe the nightmares of deploying a new software application over an existing one. The open source world has similar woes, making dependency checking tools such as RPM and APT de riguer to keep your system up-to-date.
Group common functionality together in namespaces, then group common namespaces in assemblies.
In .NET, Microsoft introduced the concept of the assembly. An assembly is simply a package of classes and resources, containing a manifest and a signature. The promise of assemblies is the end of DLL hell, allowing each application to bring along the knowledge of its dependencies as well as allowing multiple versions of the same library to coexist to serve those different applications.
Typically, when we refer to an assembly, we're referring to a DLL compiled with the -target:library command-line argument to mcs. However, you've actually been creating an assembly every time you compile any Mono executable. A Mono library is simply an assembly without a Main( ) method, while a Mono executable is an assembly with a Main( ) entry point.
What makes assemblies distinct is the metadata they contain. The metadata are part of the assembly manifest, and their values can be set both by including classes and resources in the assembly and through assembly-level attributes. The manifest includes the assembly's identity information, including the version and digital signature; a list of files included in the assembly; a list of external assemblies referenced by the assembly; public classes and resources included in the assembly; and any permissions the assembly needs to run.
Although they may be included in any source file, assembly-level attributes by convention are only included in a file called AssemblyInfo.cs. Example 2-13 shows the contents of a typical
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Core .NET
By now you've become familiar with the C# language, and you've seen some of its differences and similarities to Java and C/C++. We've alluded to some of the powerful Framework Class Library (FCL) classes, but we haven't really gone into depth on them.
In this chapter, you'll be introduced to the FCL and some of its most commonly used classes, including those that let you work with files, strings, regular expressions, collections, assemblies, process control, and threading. And, as a bonus, you'll get your first look at NUnit, the .NET unit testing framework.
File I/O is an important part of any class library, and the FCL contains a complete and powerful set of file access classes. In this lab, you'll see how to manipulate files and directories with Mono.
You need to learn three basic classes in the FCL to manage files. They are File, TextReader, and TextWriter. Example 3-1 shows the source for a class that uses these three classes to create a file, write to it, read from it, and set some of the file's attributes.
Reading, writing, and `rithmetic may be elementary skills, but Mono makes them even easier.
Example 3-1. 01-files/FileCreator.cs
// 03-keyfunc/01-files
using System;
using System.IO;

public class FileCreator {
  public static void Main(string [  ] args) {
    string file = args[0];
    
    if (File.Exists(file)) {
      Console.WriteLine("File {0} exists with attributes {1}," +
        "created at {2}", file, File.GetAttributes(file), 
        File.GetCreationTime(file));
    } else {
      using (TextWriter writer = File.CreateText(file)) {
        writer.WriteLine("Greetings from Mono!");
      }
      File.SetAttributes(file,
        File.GetAttributes(file) | FileAttributes.ReadOnly | 
        FileAttributes.Temporary);
    }
    
    using (TextReader reader = File.OpenText(file)) {
      Console.WriteLine(reader.ReadToEnd( ));
    }
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Work with Files
File I/O is an important part of any class library, and the FCL contains a complete and powerful set of file access classes. In this lab, you'll see how to manipulate files and directories with Mono.
You need to learn three basic classes in the FCL to manage files. They are File, TextReader, and TextWriter. Example 3-1 shows the source for a class that uses these three classes to create a file, write to it, read from it, and set some of the file's attributes.
Reading, writing, and `rithmetic may be elementary skills, but Mono makes them even easier.
Example 3-1. 01-files/FileCreator.cs
// 03-keyfunc/01-files
using System;
using System.IO;

public class FileCreator {
  public static void Main(string [  ] args) {
    string file = args[0];
    
    if (File.Exists(file)) {
      Console.WriteLine("File {0} exists with attributes {1}," +
        "created at {2}", file, File.GetAttributes(file), 
        File.GetCreationTime(file));
    } else {
      using (TextWriter writer = File.CreateText(file)) {
        writer.WriteLine("Greetings from Mono!");
      }
      File.SetAttributes(file,
        File.GetAttributes(file) | FileAttributes.ReadOnly | 
        FileAttributes.Temporary);
    }
    
    using (TextReader reader = File.OpenText(file)) {
      Console.WriteLine(reader.ReadToEnd( ));
    }
  }
}
There are attributes, attributes, and attributes. In Chapter 2, we told you about attributes in C#. In Chapter 6 we'll talk about XML attributes. This lab features file attributes, indicating metadata such as whether the file is to be archived, and whether it's compressed, encrypted, hidden, and others.
You should always remember to close any files you open. Luckily, TextReader and TextWriter both implement IDisposable, so you can wrap them in the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Manage String Data
Strings are first-class objects in C#. They can be created just like any other type, but you will do well to use them wisely.
Example 3-3 shows how strings are created and manipulated using the string class.
System.String, like Int32, Byte, Char, and other primitive types in the System namespace, can be referred to by an alias. For String, that's string.
Example 3-3. 02-strings/Strings.cs
// 03-keyfunc/02-strings
using System;

public class Strings {
    public static void Main(string [  ] args) {
        string s1 = "a string!";
        string s2 = @"a string with \escaped characters,
including a carriage return";
        string s3 = new String('a', 4);
        string s4 = s3 + s1;
        string s5 = s4.Replace('a', 'b');

        Console.WriteLine(s1);
        Console.WriteLine(s2);
        Console.WriteLine(s3);
        Console.WriteLine(s4);
        Console.WriteLine(s5);
    }
}
Compiling and running this program, here's what you'll see:
$ mcs Strings.cs
$ mono Strings.exe
a string!
a string with \escaped characters,
including a carriage return
aaaa
aaaaa string!
bbbbb string!
Going over these one at a time, here's how they work. The first string, s1, is assigned to the literal value "a string!". Simple enough.
The second string, s2, is prefixed with the @ character. This @-quoted (literal) string contains an embedded backslash and a carriage return. Special characters such as these typically need to be escaped using the \ and \n character sequences. By @-quoting the string, any characters that normally need to be escaped can be put in the string literally.
Unicode? Of course! Strings in Mono are stored in Unicode internally. To embed a Unicode character within a string, use the format \unnnn, where nnnn is a four-digit number, or \unnnn\unnnn for 8-digit Unicode characters
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Search Text with Regular Expressions
Perl and shell programmers have long known the power of regular expressions, a language for describing patterns in sometimes excruciating detail. But there's no substitute for a regular expression when you need to separate a fixed- or variable-format chunk of text into its components.
Parse text with obscure, magical formulae that look like a baby sat down at the keyboard.
This lab will demonstrate Mono's regular expression support.
Example 3-4 shows a program that reads a hosts file and reports on its contents using regular expressions.
The hosts file will be located in different places in different operating systems. In Linux, Unix, and Mac OS X, it will be in /etc. On Windows, it will be in %WINDIR%\System32\drivers\etc. When constructing a path, use the Path.DirectorySeparatorChar property, which gives you the character that separates directories in a path, / for Unix, \ for Windows.
Example 3-4. 03-regex/ParseHosts.cs
// 03-keyfunc/03-regex
using System;
using System.Collections;
using System.IO;
using System.Text.RegularExpressions;

public class ParseHosts {
  public static void Main(string [  ] args) {
    string filename;
    if (Environment.OSVersion.ToString( ).StartsWith("Unix")) {
      filename = string.Format("{0}etc{0}hosts", 
        Path.DirectorySeparatorChar);
    } else {
      filename = string.Format("{0}{1}drivers{1}etc{1}hosts", 
        Environment.GetFolderPath(Environment.SpecialFolder.System), 
        Path.DirectorySeparatorChar);
    }
    
    if (!File.Exists(filename)) {
      Console.Error.WriteLine("{0} does not exist.", filename);
      Environment.Exit(1);
    }
    
    string text;
    using (TextReader reader = File.OpenText(filename)) {
      text = reader.ReadToEnd( );
    }

    Regex regex = 
      new Regex(@"(?<ip>(\d{1,3}\.){3}\d{1,3})\s+(?<name>(\S+))");
    
    MatchCollection matches = regex.Matches(text);
    foreach (Match match in matches) {
      if (match.Length != 0) {
        Console.WriteLine("hostname {0} is mapped to ip address {1}",
          match.Groups["name"], match.Groups["ip"]);
      }
    }
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Manage Collections of Data
Collection types in the .NET Framework are very powerful. Besides the array type we introduced in Section 2.2, there is a whole slew of more complex and specialized types to handle almost every case where you need a collection of objects. And you can extend a base class to make your own custom collection.
Because you can never have too much of a good thing.
In this lab, we'll introduce the many ways of working with collections in Mono.
Example 3-5 shows a class that uses some of the many .NET collection types.
Example 3-5. 04-collections/PrintEnvironment.cs
// 03-keyfunc/04-collections
using System;
using System.Collections;

public class PrintEnvironment {
  public static void Main(string [  ] args) {
    IDictionary variables = Environment.GetEnvironmentVariables( );
    
    ICollection variableNames = variables.Keys;
    
    foreach (string variableName in variableNames) {
      Console.WriteLine("{0}={1}", variableName, variables[variableName]);
    }
  }
}
If you compile and run PrintEnvironment.exe, you should see something like this:
This output comes from the bash shell on Mac OS X 10.3. Your mileage may vary, especially if you're running on Windows.
$ mcs PrintEnvironment.cs
$ mono PrintEnvironment.exe
MANPATH=/sw/share/man:/usr/share/man:/usr/local/man:/usr/X11R6/man
VISUAL=/usr/bin/vi
TERM_PROGRAM=Apple_Terminal
TERM_PROGRAM_VERSION=100
OLDPWD=/Users/niel
_ _CF_USER_TEXT_ENCODING=0x1F5:0:0
XML_CATALOG_FILES=/sw/etc/xml/catalog
INFOPATH=/sw/share/info:/sw/info:/usr/share/info
LOGNAME=niel
TERM=xterm-color
USER=niel
PERL5LIB=/sw/lib/perl5:/sw/lib/perl5
_=/usr/local/bin/mono
SGML_CATALOG_FILES=/sw/etc/sgml/catalog
PWD=/Users/niel/Documents/Mono Developers Notebook/monodn
SHELL=/bin/bash
SECURITYSESSIONID=210970
HOME=/Users/niel
PATH=/sw/bin:/sw/sbin:/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin:/usr/X11R6/bin:
/usr/local/bin
SHLVL=1
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Work with Assemblies
As was already mentioned in Section 2.8, the assembly is the basic unit of deployment of a Mono library or application. In that lab, you saw how to create an assembly, how they are named, and how to store them in the GAC.
Everything's an assembly. What's in an assembly?
In this lab, you'll see how to examine the internal organization of assemblies.
You can use the monodis.exe tool to view the CIL for any assembly. For example, the SprocketSet.dll assembly, which you'll remember from Section 2.8, is made up of the classes Sprocket and Widget, along with attributes from AssemblyInfo.cs and resources from SprocketSet.resources. The contents of Sprocket.cs are:
public class Sprocket {
}
and Widget.cs contains this:
public class Widget {
        public Sprocket Sprocket;
}
Run monodis SprocketSet.dll to view the results in Example 3-7.
Common Intermediate Language is the equivalent of assembly language for the .NET framework.
Example 3-7. 05-assemblies/SprocketSet.il
.assembly extern mscorlib
{
  .ver 1:0:5000:0
}
.assembly 'SprocketSet'
{
  .custom instance void class [mscorlib]'System.Reflection.AssemblyKeyNameAttribute'
::.ctor (string) =  (01 00 00 00 00 ) // .....

  .custom instance void class [mscorlib]'System.Security.
AllowPartiallyTrustedCallersAttribute'::.ctor( ) =  (01 00 00 00 ) // ....

  .custom instance void class [mscorlib]'System.Reflection.AssemblyTitleAttribute'::.ctor
(string) =  (
    01 00 0B 53 70 72 6F 63 6B 65 74 53 65 74 00 00 ) // ...SprocketSet..

  .custom instance void class [mscorlib]'System.Reflection.AssemblyDescriptionAttribute'
::.ctor(string) =  (
    01 00 21 42 75 69 6C 64 20 53 70 72 6F 63 6B 65   // ..!Build Sprocke
    74 73 20 66 6F 72 20 79 6F 75 72 20 77 69 64 67   // ts for your widg
    65 74 73 2E 00 00                               ) // ets...

  .custom instance void class [mscorlib]'System.Reflection.AssemblyConfigurationAttribute'
::.ctor(string) =  (01 00 07 52 65 6C 65 61 73 65 00 00 ) // ...Release..

  .custom instance void class [mscorlib]'System.Reflection.AssemblyCompanyAttribute'
::.ctor(string) =  (
    01 00 13 41 6D 61 6C 67 61 6D 61 74 65 64 20 57   // ...Amalgamated W
    69 64 67 65 74 73 00 00                         ) // idgets..

  .custom instance void class [mscorlib]'System.Reflection.AssemblyProductAttribute'
::.ctor(string) =  (
    01 00 0B 53 70 72 6F 63 6B 65 74 53 65 74 00 00 ) // ...SprocketSet..

  .custom instance void class [mscorlib]'System.Reflection.AssemblyCopyrightAttribute'
::.ctor(string) =  (
    01 00 2E 32 30 30 34 20 41 6D 61 6C 67 61 6D 61   // ...2004 Amalgama
    74 65 64 20 57 69 64 67 65 74 73 2E 20 41 6C 6C   // ted Widgets. All
    20 52 69 67 68 74 73 20 52 65 73 65 72 76 65 64   //  Rights Reserved
    2E 00 00                                        ) // ...

  .custom instance void class [mscorlib]'System.Reflection.AssemblyTrademarkAttribute'
::.ctor(string) =  (01 00 00 00 00 ) // .....

  .custom instance void class [mscorlib]'System.Reflection.AssemblyCultureAttribute'
::.ctor(string) =  (01 00 05 65 6E 2D 55 53 00 00 ) // ...en-US..

  .custom instance void class [mscorlib]'System.Reflection.AssemblyDelaySignAttribute'
::.ctor(bool) =  (01 00 00 00 00 ) // .....

  .custom instance void class [mscorlib]'System.Reflection.AssemblyKeyFileAttribute'
::.ctor(string) =  (
    01 00 0F 53 70 72 6F 63 6B 65 74 53 65 74 2E 73   // ...SprocketSet.s
    6E 6B 00 00                                     ) // nk..

  .custom instance void class [mscorlib]'System.CLSCompliantAttribute'::.ctor(bool) =  
(01 00 01 00 00 ) // .....

  .hash algorithm 0x00008004
  .ver  1:0:1601:37419
  .locale en-US
  .publickey = (
    00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00   // .$..............
    00 24 00 00 52 53 41 31 00 04 00 00 11 00 00 00   // .$..RSA1........
    C3 9F ED 12 DB 31 A8 97 5A 3C D6 01 3F E6 09 22   // .....1..Z<..?.."
    76 F8 60 A0 A2 6D 49 DD 81 1C E5 12 FB 92 36 94   // v.`..mI.......6.
    93 D8 EC 6D F8 3F D1 FC 4A 02 21 B7 6F 06 BE 18   // ...m.?..J.!.o...
    56 F0 7C 6B C0 D1 07 1A A8 8F 1E FD 38 5E A6 20   // V.|k........8^. 
    FD 36 86 E0 12 BE 91 89 DB C0 C2 D6 4F 5B FD 76   // .6..........O[.v
    E1 47 16 8D 67 A0 E6 00 9E B3 A1 5B 75 09 8C 75   // .G..g......[u..u
    36 07 E8 31 E4 8B F2 6D 3B 12 28 0E 1C CC 75 45   // 6..1...m;.(...uE
    55 3B FD 55 BC 60 8E 7C 93 01 78 C6 3A 77 5E C6 ) // U;.U.`.|..x.:w^.
}
.module 'SprocketSet.dll' // GUID = {F7829D2A-5DAC-5B46-AD1D-D6CD2F7899CE}


  .class public auto ansi beforefieldinit 'Sprocket'
    extends [mscorlib]System.Object
  {

    // method line 1
    .method public hidebysig  specialname  rtspecialname 
           instance default void .ctor ( )  cil managed 
    {
        // Method begins at RVA 0x20ec
  // Code size 7 (0x7)
  .maxstack 8
  IL_0000:  ldarg.0 
  IL_0001:  call instance void valuetype [mscorlib]'System.Object'::.ctor( )
  IL_0006:  ret 
    } // end of method Sprocket::instance default void .ctor ( ) 

  } // end of type Sprocket

  .class public auto ansi beforefieldinit 'Widget'
    extends [mscorlib]System.Object
  {
    .field  public   class 'Sprocket' 'Sprocket'

    // method line 2
    .method public hidebysig  specialname  rtspecialname 
           instance default void .ctor ( )  cil managed 
    {
        // Method begins at RVA 0x20f4
  // Code size 7 (0x7)
  .maxstack 8
  IL_0000:  ldarg.0 
  IL_0001:  call instance void valuetype [mscorlib]'System.Object'::.ctor( )
  IL_0006:  ret 
    } // end of method Widget::instance default void .ctor ( ) 

  } // end of type Widget
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Start and Examine Processes
Often, a program needs to spawn other processes in order to get a job done. Unix programmers are familiar with the old fork( ) and exec( ) routine. Mono has equivalent functionality, and the same classes can be used to examine the state of other processes currently running.
In this lab, you'll see how to spawn processes, and how to look at the other processes currently running on your machine.
Example 3-8 shows a program that runs the Unix sleep command, taking the number of seconds to sleep from a command-line argument.
Example 3-8. 06-process/StartProcess.cs
// 03-keyfunc/06-process
using System;
using System.Diagnostics;

public class StartProcess {
  public static void Main(string [  ] args) {
    string sleepTime = args[0];
    
    ProcessStartInfo startInfo = new ProcessStartInfo( );
    startInfo.FileName = "sleep";
    startInfo.Arguments = sleepTime;
    Console.WriteLine("Starting {0} {1} at {2}", 
      startInfo.FileName, startInfo.Arguments, DateTime.Now);
    Process process = Process.Start(startInfo);
    process.WaitForExit( );
    Console.WriteLine("Done at {0}", DateTime.Now);
  }
}
Compile and run StartProcess.cs with the following command lines:
$ mcs StartProcess.cs
$ mono StartProcess.exe 10
Starting sleep 10 at Wednesday, 12 May 2004 21:24:47
Done at Wednesday, 12 May 2004 21:24:58
You can see that sleep 10 was called, and that the start and end times were printed to standard output.
Example 3-9 contains another program using the Process class. This program, ListProcesses, lists all processes running on the machine, with their process ID, name, and start time.
Consciousness is a state of awareness of self and environment. Mono's got that.
Example 3-9. 06-process/ListProcesses.cs
using System;
using System.Diagnostics;

public class ListProcesses {
  public static void Main(string [  ] args) {
    foreach (Process process in Process.GetProcesses( )) {
      Console.WriteLine("Process {0}: {1} on {2} started at {3}", 
        process.Id, process.ProcessName, process.MachineName, 
        process.StartTime);
    }
  }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Multitask with Threads
Content preview·Buy PDF of this chapter|