Monthly Archives: August 2012

MVC 4 – Adding a database

In the last post, we saw how to set up an MVC4 web site in Visual Studio 2012, and how to add a simple controller and view to it.

Most web sites that do anything more than display a bit of fixed information have a database behind them. For example, a blog is backed by a database that stores the posts, a shop contains information on products available in a database and so on.

In this post, we’ll expand our ComicShop site so it contains a database that stores information about comics in stock. There are many databases available, but for now we’ll take the easiest route and use SQL Server Compact Edition, which is included with VS2012. This database has the advantage that it doesn’t require a separate server running in the background; it stores its data in a local file and accesses this file whenever it needs to update the data.

Most of the web sites and books I looked at contained instructions for installing a SQL Server CE database and connecting it with an MVC4 project, but unfortunately, if you start from an Empty project in VS2012, these methods didn’t work: the first attempt to access the database threw an exception complaining that it was unable to attach the database file.

Eventually I tracked down the problem, so in this post I’ll show how to connect a simple database to an MVC4 project.

We’ll begin by creating the database, and then add a controller and a view that allows us to add data to it.

Starting with our ComicShop project from the last post, in Solution Explorer, right-click on App_Data and select Add –> SQL Server Compact 4.0 Local Database. Name this database ComicBooks. You should see a database appear under the App_Data folder. Double-click on this file to open the Server Explorer. Open the ComicBooks node and right-click on Tables, then select Create Table. In the dialog that appears, name the table Books.

Now create some columns in this table, as follows. First, we create a primary key for the table, which we’ll call Id. Enter Id as the column name, set its Data Type to int, then set Primary Key to Yes and Unique to Yes. (The Allow Nulls value should automatically become No during this process.) In the box at the bottom of the dialog, set its Identity to True. This will make Id an auto-incrementing field, so every time you add a record to the table, Id will automatically increase by 1.

Now add a Title column, setting its Data Type to nvarchar, then a Volume column, setting its Data Type to int. Then Issue, also an int. Finally, add a Publisher column, setting its data type to nvarchar. Click on OK to close the dialog.

Just to verify that the table has been created properly, open the Tables node in Server Explorer, right-click on the Books table and select Show Table Data. You should see a window showing one row with the columns you just defined, each containing a NULL entry.

Now that we have our database defined, we need a way of putting data into it. One way is to edit the data table in the Show Data Table window directly, but that obviously isn’t much use if you want to edit the data via the web site. So we need to add a controller and view that allows access to the database via a web page.

First, we need a class to store the data fields for a single comic book. This class will mirror the structure of the database. Since it stores data, it belongs in the Models folder, so right-click on Models in Solution Explorer and select Add–>Class. Call the class Book, and enter some properties to match those in the database:

namespace ComicShop.Models
{
  public class Book
  {
    public int Id { get; set; }
    public string Title { get; set; }
    public int Volume { get; set; }
    public int Issue { get; set; }
    public string Publisher { get; set; }
  }
}

Next, we need a way of connecting the C# code to the database. The easiest way (well, after we know what to do…it took a lot of searching to find the right way of doing it!) is to use a DbContext. Add another class called ComicContext to the Models folder, with code as follows (I’ll explain this code in more detail later):

using System.Data.Entity;

namespace ComicShop.Models
{
  public class ComicContext : DbContext
  {
    public ComicContext(string conn)
      : base(conn)
    {
    }

    public DbSet<Book> ComicBooks { get; set; }
  }
}

You will notice that VS complains that System.Data.Entity doesn’t exist. You might think that the usual solution of adding this namespace in your References list will fix the problem, but even though System.Data.Entity does exist in the list of assemblies you can add to References, adding it doesn’t help much: VS still complains that it can’t find DbContext (even though the online documentation says that it is part of System.Data.Entity).

The solution turns out to require the addition of a NuGet package. To do this, right-click on References in Solution Explorer and select Manage NuGet Packages (if this option doesn’t exist, you’ll need to install NuGet from nuget.org). Select Online on the left, and enter EntityFramework in the search box in the upper right. After the search engine finds it, check that it’s version 5.0.0 of EntityFramework, then click on Install. At this point, everything should compile properly. (For the curious, EntityFramework is a huge topic in its own right, so we won’t go into that here.)

We also need to install another NuGet package to allow us to use SQL Server CE, so while you’ve got NuGet open, do a search for EntityFramework.SqlServerCompact. This should return only a single result, so install that and then close the NuGet dialog.

We’ve now got the model classes set up so we need to add the controller and view to allow data to be input. Open HomeController.cs (which we created in the last post). Remember that each method in this controller corresponds to a separate URL that the user can visit in your web site. The Index() method gives the home page which we saw last time.

We want to add a page for entering data for a comic book, so we’ll write an Add() method. The code is much the same as for Index():

        public ActionResult Add()
        {
          return View();
        }

Right-click in this method and select Add View, accepting the default name of Add. We’ll keep things simple by knocking up a basic HTML form; it’s not pretty but we can worry about that later. Right now we just want to get the site working. The code is

@{
    ViewBag.Title = "Add comic";
}

<h2>Add new comic</h2>
<form method="post">
    <fieldset>
        <legend>Add comic form</legend>
        Title: <input type="text" name="Title" maxlength="100" />
        <br />
        Volume: <input type="number" name="Volume" />
        <br />
        Issue: <input type="number" name="Issue" />
        <br />
        Publisher: <input type="text" name="Publisher" />
        <br /><br />
        <input type="submit" value="Submit Comic" />
    </fieldset>
</form>

This produces four input boxes for entering the four bits of data required for a comic book, and then displays a submit button at the bottom, which returns the entered data back to the web server.

Note that we’ve named each input element so that its name matches the corresponding field in the Book class (and hence the column in the database); this is important for the connection to work properly.

The last link in the chain is the handler for the data submitted by the form. To enable communication with the database, we need to let the web server know where to find the database file. This requires adding a bit to the web.config file for the project. Open Web.config in Solution Explorer (Note that there are two web.config files, one at the top level and one inside the Views folder. It’s the top-level one we want.) At the end of the file, just above the closing </configuration> tag, insert the following:

  <connectionStrings>
    <add name="ComicContextDb" connectionString="Data Source=|DataDirectory|\ComicBooks.sdf" providerName="System.Data.SqlServerCe.4.0"/>
  </connectionStrings>

(This assumes you’ve followed the instructions above and created your database file under App_Data with the name ComicBooks.) This defines a connection to the database file called ComicContextDb, and specifies that it is a SQL Server CE database.

Now we can write the handler for the data sent back by the form. To do this, we add a bit more code to the HomeController class:

    private ComicContext database = new ComicContext("ComicContextDb");
    [HttpPost]
    public ActionResult Add(Book book)
    {
      database.ComicBooks.Add(book);
      database.SaveChanges();
      return Content("New comic added.");
    }

We create an instance of our ComicContext model class and pass it the name of the connection that we defined in web.config above. If you look at the code for ComicContext above, you’ll see that this string is passed back to the base class (DbContext), which takes care of the interaction with the database, so this base class will use the connection string to establish a link with the database.

Another important point is that the data type (in this case Book) specified in the DbSet object in ComicContext is the singular of the name of the table (Books) in the database. This is actually required in order for the link to work properly. In fact, if we had specified a different class name in DbSet, a table with that name with an ‘s’ added at the end would be created within the database automatically. In general, if you change the underlying model code that links with the database after the database has been created, you’ll need to invoke a ‘migration’ process to update the database so it is in sync with the new code. We won’t go into that here, but just be aware that making changes isn’t entirely straightforward.

Returning to our second Add() method above, note that it is prefixed by an [HttpPost] tag. This indicates that the method is a handler for data returned from the Add page via the HTTP post protocol. The returned data is used to create a Book object (by matching up the control names with the Book’s field names, as mentioned above) which is then passed into the Add() method as its parameter.

The first line of Add() adds the new Book object to the ComicBooks DbSet of the database object, and the next line saves the changes to the database itself. If you’ve done any database programming before, it’s at this point that you would normally write SQL statements for inserting a new record into the database, but the DbContext and DbSet classes do all this for you.

Finally, we return a Content object that prints a message saying “New comic added.”. Obviously in a proper web site we’d want something a bit fancier than that, but at this stage that’s all we need to see that it works.

If you now start the site running and then enter the URL localhost:36195/Home/Add, (your port number might be different), you should see the form for entering some data for a new comic book. Fill in some data and press the submit button, and if all goes well, you should see the “New comic added.” message.

We haven’t provided any way of seeing the contents of the database on the web site yet, but to verify that the comic you just entered did in fact make it into the database, you can use the Show Table Data command to look at the Books table.

 

MVC 4 – An Introduction

I’ve started looking at the MVC 4 platform for developing web sites in ASP.NET, so I’ll record my experiences as I go along.

First, an introduction to the ideas behind MVC would be useful.

MVC stands for Model-View-Controller, and is a popular design pattern used in structuring medium to large programs. Its use is not restricted to ASP.NET or to web development; in fact it’s something of an industry standard for many software development projects.

The concept is fairly simple, and is based on the idea that the main functions within a program should be separated, since this makes it easier to assign different people to different tasks, as well as making the code easier to understand and maintain.

In many programs, there is a collection of data which can be viewed in various ways. For example, in a word processor, the data consists of the text and images contained within the document. This data can be viewed in various ways: in edit mode where changes can be made, in print preview mode where the user sees what the document will look like when printed, in outline mode where only the section headers are shown, and so forth. In all these views the underlying data – the model – remains the same. Thus to put it simply, the model is the information stored in a program and the view is how it looks to the user.

The controller is a bit more vague, but in essence it’s the code that links the model to the view. In a program with various user interaction controls such as buttons and menus, the controller consists of the event handlers that process the user’s actions. For example, if the user presses the Print Preview button in a word processor, the controller processes this action by retrieving the document from the model and passing it to the view that displays a print preview.

In the particular case of MVC as applied to ASP.NET (rather confusingly, MVC can refer to the generic design pattern as used in any type of program and also to the specific implementation in ASP.NET), the model stores the data (in C# data structures or possibly in a database) and the view generates the HTML which allows the user to view the data in some form. The controller responds to a user’s request for a web page by retrieving whatever data is required from the model and then passing this to a view which constructs the web page that is sent back to the user.

That’s really about all you need to understand about MVC to get started. From here on, it’s easiest if we use an actual example to demonstrate how to build an MVC project. In what follows, I’m using Visual Studio 2012 (version 11 of Visual Studio), which has support for MVC 4 built in. If you’re using VS2010, you’ll need to download and install MVC 4 support as an add-on. This should be freely available from Microsoft’s web site – as always, Google is your friend here.

Even in VS2012, however, the first time I tried to create an MVC 4 project, I got an error saying that the NuGet package wasn’t found. This is easily fixed by visiting nuget.org and installing the package.

Assuming you’ve got VS set up properly, begin by creating a new project. In the New Project dialog, select ASP.NET MVC 4 Web Application. We’ll look at building a web site for a comic shop, so call the project ComicShop and click OK. You’ll then see the New ASP.NET MVC 4 Project dialog, which offers several options for your new project. Internet Application is pre-selected, and if you go with this you’ll get the outline of a functional web site with pages for creating accounts, logging in and so on. All of this functionality can be a bit daunting at first, so we’ll start with the Empty template.

Even with an empty project you get a fair number of files. In Solution Explorer, have a look at the folders that have been created; you’ll see among them folders for Controllers, Models and Views and as you might guess, that’s where most of your work will be done.

If you try running the project at this point by pressing Control+F5 to start without debugging, what should happen is a page will open in your default browser (I use Google Chrome, but this should work with whatever your default browser is). Visual Studio will start up a local web server for the purposes of testing your project and attempt to display the home page of this site in the browser.

At this stage you’ll get an error message saying the the page at ‘/’ (the root of the web site) couldn’t be found. This isn’t terribly surprising, since we haven’t added any pages to the site yet.

So where do we start? First we need to understand a bit about how MVC handles naming conventions. The conventional name for a controller class is <Path>Controller, where <Path> is the part of the URL following the site’s address. For example, with the local server created by VS, the home page might have the URL localhost:30844/Home/Index. In this case, the controller class that handles the request for the page is HomeController. (We’ll deal with the Index part in a minute.)

Let’s add a controller to the project in an attempt to get a home page. In Solution Explorer, right-click on the Controllers folder and select Add –> Controller. In the dialog that appears, name the controller HomeController and select Empty MVC controller for the template, then click Add. You’ll see the file HomeController.cs appear in the Controllers folder, and the class file will be displayed in the code editor. It should look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace ComicShop.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }

    }
}

Before we explain anything, try running your project again. You’ll still get an error, but this time it’s complaining that it can’t find a view. To fix this, right-click on the Index() method and select Add view. Accept the default name of Index and click Add. You’ll see another file appear in the code editor, but ignore that for now. Now try running the project again.

This time, you should get a page in the browser with the word ‘Index’ in a big, bold font at the top. Congratulations – you now have a functioning web site! OK, it’s not particularly informative, but it’s a start.

Now for a bit of explanation as to what has happened. The most obvious question is probably: How did the web server know to display the page with Index on it? After all, we could have called our controller anything at all, and not just HomeController, and we never specified Home in the browser – the page just magically appeared.

Actually, if we had called the controller something else, it wouldn’t have worked. To see why, look in Solution Explorer and open the folder called App_Start. Inside this, open the file RouteConfig.cs. You’ll see this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace ComicShop
{
  public class RouteConfig
  {
    public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

      routes.MapRoute(
          name: "Default",
          url: "{controller}/{action}/{id}",
          defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
      );
    }
  }
}

The routes.MapRoute() call defines what the default URL will be. The ‘url’ parameter says that the default format for a URL is ”{controller}/{action}/{id}”, and the ‘defaults’ line says the default controller name is Home and the default action name is Index. The last entry says that ‘id’ is optional.

What this means is that if we don’t specify a URL, the request to the server is taken to be for the page /Home/Index, and that the controller called HomeController should be called for this. Within this controller, the action called Index should be called. (The ‘id’ is an optional bit of information we can tack on to the URL, but more on that later.)

What is happening, then, is that the server is started up and looks for a controller called HomeController and then for an action called Index within that controller.

That action, at the moment, returns the result of a call to View(), and as you’ve probably guessed, that uses the code in the Index.cshtml file that you created above when you added a view to the Index() method to generate the HTML which is sent back to the browser. If you know a bit of HTML syntax, you’ll see that all this page does is print Index, which is in fact what you’ve seen.

LINQ: ToDictionary

Up till now, we’ve considered only the deferred standard query operators, which are not evaluated until their result is actually enumerated by, for example, running through the result in a foreach loop.

LINQ also has a number of non-deferred operators, which are evaluated at the point where they are called. The first of these we’ll look at is  ToDictionary.

C# has a built in Dictionary data type, which is an implementation of a hash table. A hash table is essentially a glorified array, with the main difference being that any data type can be used as the array index or key. For example, if we wanted to store our list of Canadian prime ministers in a dictionary, we could use the integer ID we’ve assigned each prime minister as the key, or we could use the person’s last name, or even define some other data type from the components of a PrimeMinisters object. The one essential property is that each key must be unique, so that only one prime minister is stored for each key.

LINQ allows a dictionary to be constructed from an IEnumerable<T> source, where T is the data type of the objects in the input sequence. The simplest version of ToDictionary allows only the key to be defined for each element in the input sequence. An example is

      PrimeMinisters[] primeMinisters = PrimeMinisters.GetPrimeMinistersArray();
      var pmDictionary01 = primeMinisters.ToDictionary(k => k.id);
      Console.WriteLine("----->pmDictionary01");
      foreach (int key in pmDictionary01.Keys)
      {
        Console.WriteLine("Prime minister with ID {0}: {1} {2}",
          key, pmDictionary01[key].firstName, pmDictionary01[key].lastName);
      }

ToDictionary() here takes a single argument, which is a lambda expression defining the key. The variable k is an element from the input sequence, and we’ve selected the ‘id’ field from that element to use as the key.

Once the dictionary is built, we use a foreach loop to run through the list by selecting each key from the Keys property of the dictionary. We use array-like notation (square brackets) to reference an element in the dictionary. Each element in the dictionary is an object of type PrimeMinsters.

The output is:

----->pmDictionary01
Prime minister with ID 1: John Macdonald
Prime minister with ID 2: Alexander Mackenzie
Prime minister with ID 3: John Abbott
Prime minister with ID 4: John Thompson
Prime minister with ID 5: Mackenzie Bowell
Prime minister with ID 6: Charles Tupper
Prime minister with ID 7: Wilfrid Laurier
Prime minister with ID 8: Robert Borden
Prime minister with ID 9: Arthur Meighen
Prime minister with ID 10: William Mackenzie King
Prime minister with ID 11: Richard Bennett
Prime minister with ID 12: Louis St. Laurent
Prime minister with ID 13: John Diefenbaker
Prime minister with ID 14: Lester Pearson
Prime minister with ID 15: Pierre Trudeau
Prime minister with ID 16: Joe Clark
Prime minister with ID 17: John Turner
Prime minister with ID 18: Brian Mulroney
Prime minister with ID 19: Kim Campbell
Prime minister with ID 20: Jean Chrétien
Prime minister with ID 21: Paul Martin
Prime minister with ID 22: Stephen Harper

There are three more variants of ToDictionary, each offering a bit more flexibility than the basic version.

A second type allows the specification of a comparer class which can be used for defining the equality of objects used as keys. In the previous example, the default definition of equality was used; since the keys were ints, two keys were equal if they had the same numerical value.

However, it is possible to define keys to be equal based on any criterion we like. For example, if we stored the ID of each prime minister as a string instead of an int, then we could define two keys to be equal if their strings parsed to the same numerical value. This would allow the strings 12 and 00012 to be equal as keys, since the leading zeroes don’t change the numerical value.

To use this feature, we must first define a comparer class, in much the same way as we did when comparing the terms of office. The comparer class here is

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqObjects01
{
  class IdKeyEqualityComparer : IEqualityComparer<string>
  {
    public bool Equals(string x, string y)
    {
      return Int32.Parse(x) == Int32.Parse(y);
    }

    public int GetHashCode(string obj)
    {
      return (Int32.Parse(obj)).GetHashCode();
    }
  }
}

Remember that we need to implement IEqualityComparer<string> and provide an Equals() and GetHashCode() method. In Equals() we parse the two strings and define equality to be true if their numerical values are equal. GetHashCode() must return the same code for two objects that are considered equal, so we call GetHashCode() on the parsed int.

With this class in hand, we can use it in the second form of ToDictionary:

      PrimeMinisters[] primeMinisters = PrimeMinisters.GetPrimeMinistersArray();
      var pmDictionary02 = primeMinisters.ToDictionary(k => k.id.ToString(),
        new IdKeyEqualityComparer());
      Console.WriteLine("----->pmDictionary02");
      foreach (string key in pmDictionary02.Keys)
      {
        string zeroKey = "000" + key;
        Console.WriteLine("Prime minister with ID {0}: {1} {2}",
          key, pmDictionary02[zeroKey].firstName, pmDictionary02[zeroKey].lastName);
      }

This time, we store the key as a string and pass an IdKeyEqualityComparer as the second parameter to ToDictionary. When we print out the results, we create a different string by prepending three zeroes onto the key in the dictionary, then use that zeroKey as the key when looking up entries in the dictionary. The dictionary uses its comparer object to compare zeroKey to the valid keys in the dictionary, and if a match is found, the corresponding object is returned. The output from this code is the same as that above.

If no match is found an exception is thrown, as you might expect, so be careful to ensure that all keys used to access the dictionary are valid.

The third variant of ToDictionary allows us to create our own data type from the sequence element being processed and store that new data type in the dictionary. For example, suppose we wanted to store the string representation of each prime minister in the dictionary instead of the original PrimeMinisters object. We can do that using the following code.

      PrimeMinisters[] primeMinisters = PrimeMinisters.GetPrimeMinistersArray();
      var pmDictionary03 = primeMinisters.ToDictionary(k => k.id,
        k => k.ToString());
      Console.WriteLine("----->pmDictionary03");
      foreach (int key in pmDictionary03.Keys)
      {
        Console.WriteLine(pmDictionary03[key]);
      }

The first argument to ToDictionary specifies the key as usual (we’ve gone back to using the int version of the key). The second parameter calls the ToString() method to produce a string which is stored in the dictionary. When we list the elements in the dictionary, we print out the entry directly, since it’s a string and not a compound object.

This time the output is:

----->pmDictionary03
1. John Macdonald (Conservative)
2. Alexander Mackenzie (Liberal)
3. John Abbott (Conservative)
4. John Thompson (Conservative)
5. Mackenzie Bowell (Conservative)
6. Charles Tupper (Conservative)
7. Wilfrid Laurier (Liberal)
8. Robert Borden (Conservative)
9. Arthur Meighen (Conservative)
10. William Mackenzie King (Liberal)
11. Richard Bennett (Conservative)
12. Louis St. Laurent (Liberal)
13. John Diefenbaker (Conservative)
14. Lester Pearson (Liberal)
15. Pierre Trudeau (Liberal)
16. Joe Clark (Conservative)
17. John Turner (Liberal)
18. Brian Mulroney (Conservative)
19. Kim Campbell (Conservative)
20. Jean Chrétien (Liberal)
21. Paul Martin (Liberal)
22. Stephen Harper (Conservative)

A final version of ToDictionary combines the last two versions, so we can provide both a key comparer and a custom data type. For example, if we wanted to store keys as strings and store the string version of each PrimeMinisters object, we could write:

      PrimeMinisters[] primeMinisters = PrimeMinisters.GetPrimeMinistersArray();
      var pmDictionary04 = primeMinisters.ToDictionary(k => k.id.ToString(),
        k => k.ToString(), new IdKeyEqualityComparer());
      Console.WriteLine("----->pmDictionary04");
      foreach (string key in pmDictionary04.Keys)
      {
        string zeroKey = "000" + key;
        Console.WriteLine(pmDictionary04[zeroKey]);
      }

The output from this is the same as from pmDictionary03.

LINQ: Cast and OfType

All the LINQ operations we’ve seen so far have worked on lists of type IEnumerable<T>, where T is the data type of the objects in the list. This is fine for most of the current data types in C#, such as the generic List<T> and the C# array. However, some older data types, such as the ArrayList, do not implement IEnumerable<T>; rather they implement the older, non-generic IEnumerable interface. If we want to use these older data types with LINQ, we must convert them to IEnumerable<T>.

There are two methods that can be used to do this: Cast<T> and OfType<T>. Let’s look at Cast<T> first.

Using our list of Canadian prime ministers, we can call the method that returns an ArrayList instead of an array. To apply LINQ operators to this list, we need to cast it first:

      ArrayList pmArrayList01 = PrimeMinisters.GetPrimeMinistersArrayList();

      var sorted = pmArrayList01.Cast<PrimeMinisters>().OrderBy(pm => pm.lastName);
      Console.WriteLine("*** cast ArrayList");
      foreach (var pm in sorted)
      {
        Console.WriteLine("{0}, {1}", pm.lastName, pm.firstName);
      }

If we tried to call OrderBy() directly on pmArrayList01, we would find that the code wouldn’t compile. If you’re using Visual Studio’s Intellisense, you’ll also notice that most of the LINQ functions don’t show up in the list anyway. The problem is that the ArrayList is not an IEnumerable<T>.

We call Cast<PrimeMinisters> on this list first, followed by a call to OrderBy() to sort the list by last name. Thus the general rule is that the object calling Cast<T> must implement IEnumerable, and the output from Cast<T> is of type IEnumerable<T>.

With this code, we get the expected output:

Abbott, John
Bennett, Richard
Borden, Robert
Bowell, Mackenzie
Campbell, Kim
Chrétien, Jean
Clark, Joe
Diefenbaker, John
Harper, Stephen
Laurier, Wilfrid
Macdonald, John
Mackenzie, Alexander
Mackenzie King, William
Martin, Paul
Meighen, Arthur
Mulroney, Brian
Pearson, Lester
St. Laurent, Louis
Thompson, John
Trudeau, Pierre
Tupper, Charles
Turner, John

Now, an ArrayList can store items of any data type (it’s defined to accept the generic ‘object’ type), so we could mix things up a bit and add some ordinary strings onto the end of the list of prime ministers. That is, we could try something like adding this code after that above:

      pmArrayList01.Add("A string item");
      pmArrayList01.Add("Isn't this interesting?");
      pmArrayList01.Add("End of list");
      sorted = pmArrayList01.Cast<PrimeMinisters>().OrderBy(pm => pm.lastName);
      foreach (var pm in sorted)
      {
        Console.WriteLine("{0}, {1}", pm.lastName, pm.firstName);
      }

There’s an obvious problem in that the three strings we’ve added at the end don’t have a firstName and lastName field, so we wouldn’t expect the code to run anyway. However, we find that code does in fact compile without errors. If we try to run it, we get the following error:

Unhandled Exception: System.InvalidCastException: Unable to cast object of type
'System.String' to type 'LinqObjects01.PrimeMinisters'.

The problem is that the Cast<PrimeMinisters> method requires that all elements in the list passed to it are of type PrimeMinisters, and it throws an InvalidCastException if any elements in the input list aren’t of the correct type.

There is one important point about Cast<T>: remember that it is a deferred operator, so it isn’t actually executed until an attempt is made to enumerate its output. That is, if we omit the foreach loop in the above code, but retain the (erroneous) call to Cast<PrimeMinisters>, the code will compile and run, seemingly without errors, since we haven’t attempted to enumerate the ‘sorted’ object. The actual exception is thrown only in the foreach loop when we try to enumerate the elements of ‘sorted’.

If we want to handle lists that contain mixed types, we can use the OfType<T> method instead. This method accepts input IEnumerable objects containing any mixture of types, and looks for those of type T. It will add these objects to its output list and ignore any objects that aren’t of type T. So we can try the following on our mixed ArrayList:

      pmArrayList01.Add("A string item");
      pmArrayList01.Add("Isn't this interesting?");
      pmArrayList01.Add("End of list");

      var sorted = pmArrayList01.OfType<PrimeMinisters>().OrderBy(pm => pm.lastName);
      foreach (var pm in sorted)
      {
        Console.WriteLine("{0}, {1}", pm.lastName, pm.firstName);
      }

      var sortedStrings = pmArrayList01.OfType<string>().OrderBy(pm => pm);
      foreach (var pm in sortedStrings)
      {
        Console.WriteLine(pm);
      }

After adding the strings, we first call OfType<PrimeMinisters> and pass the result to OrderBy. The OfType call will look only for elements in the ArrayList of type PrimeMinisters, and ignore the string objects. Thus the list passed to OrderBy contains only the correct type, and the ordering and subsequent foreach loop both work properly. The results of this foreach loop are the same as with our original Cast above.

In the last bit of code, we use OfType<string>, which throws away all the PrimeMinisters objects and saves the three strings. Of course, we have to change the predicate in OrderBy so it operates on a simple string rather than a PrimeMinisters object, and similarly for the WriteLine() in the foreach loop. The output of this final loop is:

A string item
End of list
Isn't this interesting?

The Cast and OfType operators can also be applied to IEnumerable lists. Cast isn’t much use in this regard, since if we start off with an IEnumerable, we don’t need to convert it to the same list. However, OfType is useful as a filter, since it can be used to create a list of a specific data type from a more generic starting list.

For example, if we create an (somewhat contrived, admittedly) array of type ‘object’ which contains both PrimeMinisters objects and strings, by putting the following method in our PrimeMinisters class:

    public static object[] GetObjectArray()
    {
      object[] pmArray = new object[GetPrimeMinistersArrayList().Count + 3];
      object[] temp = (object[])GetPrimeMinistersArrayList().ToArray(typeof(PrimeMinisters));
      for (int i = 0; i < temp.Count(); i++)
      {
        pmArray[i] = temp[i];
      }
      pmArray[pmArray.Count() - 3] = "String 1";
      pmArray[pmArray.Count() - 2] = "String 2";
      pmArray[pmArray.Count() - 1] = "String 3";
      return pmArray;
    }

We can isolate the PrimeMinisters objects by using OfType on the object[] array (remember that a C# array is an IEnumerable<T>).

      object[] pmArray01 = PrimeMinisters.GetObjectArray();
      var sortedArray = pmArray01.OfType<PrimeMinisters>().OrderBy(pm => pm.lastName);
      foreach (var pm in sortedArray)
      {
        Console.WriteLine("{0}, {1}", pm.lastName, pm.firstName);
      }

Finally, it’s worth noting that there is a third conversion operator called AsEnumerable<T> which does take an IEnumerable<T> as input and produces another IEnumerable<T> as output. Although this may seem pointless, it’s actually essential when we deal with databases. But we’ll leave that until we consider the use of LINQ with databases.

Follow

Get every new post delivered to your Inbox.