Share via


Visual Studio 2010: Delegates, Generic IEnumerable

image

This is kind of a re-blog. My goal is to have a more specific blog than before.

 

image

 

Generic Delegates

Let’s warm up with some generic delegates to start getting used to some of the code. Lines 23 to 26 we build a collection of delegate functions that we later loop through and execute.
    1:          public static int Method1()
    2:          {
    3:              Trace.WriteLine("Invoked Method1");
    4:              return 1;
    5:          }
    6:          public static int Method2()
    7:          {
    8:              Trace.WriteLine("Invoked Method2");
    9:              return 1;
   10:          }
   11:          public static int Method3()
   12:          {
   13:              Trace.WriteLine("Invoked Method3");
   14:              return 1;
   15:          }
   16:          // Code to demonstrate delegate usage
   17:          private void cmdGenericDelegates_Click(object sender, EventArgs e)
   18:          {
   19:              Func<int> brunoDelegate1 = Method1;
   20:              Func<int> brunoDelegate2 = Method2;
   21:              Func<int> brunoDelegate3 = Method3;
   22:   
   23:              Func<int> totalDelegates =
   24:                      brunoDelegate1 +
   25:                      brunoDelegate2 +
   26:                      brunoDelegate3;
   27:   
   28:              Delegate[] delegateList = totalDelegates.GetInvocationList();
   29:              foreach (Func<int> curr_instance in delegateList)
   30:              {
   31:                  curr_instance();   // Basically, this runs Method1(), Method2(), Method3()
   32:              }
   33:          }

The point here is the curr_instance() will call all 3 methods:

delegateList is essentially an array of refererences to methods:

 

Sample Code: Building a data model to experiment with

We need to define some basic patterns to illustrate our points.
    1:  public class Person
    2:  {
    3:      public Person(string fName, string lName)
    4:      {
    5:          this.firstName = fName;
    6:          this.lastName = lName;
    7:      }
    8:      public virtual void Show()
    9:      {
   10:          Trace.WriteLine("Name is " + firstName + " " + lastName);
   11:      }
   12:      public string firstName;
   13:      public string lastName;
   14:  }
   15:  public class Employee : Person
   16:  {
   17:      public Employee(string title, string fName, string lName)
   18:          : base(fName, lName)
   19:      {
   20:          this.title = title;
   21:      }
   22:      public override void Show()
   23:      {
   24:          base.Show();
   25:          Trace.WriteLine("Title is " + title);
   26:      }
   27:      public string title;
   28:  }
   29:  public class Manager : Person
   30:  {
   31:      public Manager(int numberEmployees, string fName, string lName)
   32:          : base(fName, lName)
   33:      {
   34:          this.numberEmployees = numberEmployees;
   35:      }
   36:      public int numberEmployees;
   37:  }
   38:  //
   39:  //Make the class People enumerable on Person
   40:  //
   41:  public class People : IEnumerable<Person>
   42:  {
   43:      private Person[] people;
   44:      public People(Person[] pArray)
   45:      {
   46:          people = new Person[pArray.Length];
   47:          for (int i = 0; i < pArray.Length; i++)
   48:          {
   49:              people[i] = pArray[i];
   50:          }
   51:      }
   52:      //This enumerator returns a list of person objects,
   53:      //one at a time.
   54:      public IEnumerator<Person> GetEnumerator()
   55:      {
   56:          foreach (Person p in people)
   57:          {
   58:              yield return p;
   59:          }
   60:      }
   61:      // Needed for to make compiler happy, but not used in my code.
   62:      IEnumerator IEnumerable.GetEnumerator()
   63:      {
   64:          foreach (Person p in people)
   65:          {
   66:              yield return p;
   67:          }
   68:      }
   69:  }

Generic Enumerators

Just code to exercise enumerators and how they work with generics.

 

Challenges: How type safety is enforced in VS 2010

What is legal and not legal when it comes to subclassing with generics

The scenario we are trying understand well is that we want generics to wok with the same we get concrete types to work.

Let's start with the concrete types. Suppose you have 2 classes as follows:

This has always been legal in C# 3.0

But this is not legal

 

However when dealing with generics, in spite of what your intuition would tell you, this is not legal:

 

This is needed because we don't know if we are going to add a "SubContractor," which might also be derived class of a person.

Imagine a scenario where you have an array like this:

Imagine loop through this array and trying to access the "Salary." Everything works fine until you get to the "SubContractor," where "Hours" and "HourlyRate" are the data elements. We'd get a crash.

That is what the type system is protecting us from.

 

 

 

Comments

  • Anonymous
    July 23, 2009
    I disagree completely with your conclusion, and here's why:  The example you give is looping over a collection of Person looking for a Salary property.  If the Salary property is not part of the base class Person and only part of the subclass Employee, then the compiler error should be that the base class Person does not have a Salary field. The last compiler error in your post is, in fact, a lie from the compiler, and the only reason a compiler would lie is if it has a bug.  Since converting an Employee to a Person is always legal, then we are guaranteed that converting a List<Employee> to an IList<Person> is always safe, and any claim by the compiler that it might not be safe is factually incorrect.  Obviously, since our variables are now declared as type Person and not as type Employee, we only have access to those members which are included in the base class, which is exactly what happens when we perform the same cast on a single item.  That, therefore, is the final proof of a compiler bug, handling an identical situation differently just because we happen to be inside a generic collection.

  • Anonymous
    July 23, 2009
    Hey, this blog template is badly messed up in firefox.

  • Anonymous
    July 24, 2009
    Will respond to both issues very soon.