Archive
Sorting Generic Lists
One of the things I like best about the use of Generics is the ability to define your own sorting functionality and apply it to a List. Much in the same way you can predefine your own Find mechanism using predicates, you can establish a way to sort your list of Generics when they don’t contain native datatypes such as int or string.
In this example we’ll take a look at how to sort a Generic list using the IComparer interface.
First of all, let’s establish a class of type Dog, and give it three properties. The first property we’ll call Species, and the next property we’ll call Age. The final property we’ll call Name.
public class Dog
{
private int _age;
private string _species;
private string _name;
public string Name
{
get{ return _name; }
set{ _name = value; }
}
public int Age
{
get{ return _age; }
set{ _age = value; }
}
public string Species
{
get{ return _species; }
set{ _species = value; }
}
}
Now that we have that we can create a list of four dogs like so:
Dog max = new Dog();
max.Age = 8;
max.Species = “Labrador”
max.Name = “Max”
Dog spike = new Dog();
spike.Age = 3;
spike.Species = “Rottweiler”
spike.Name = “Spike”
Dog princess = new Dog();
princess.Age = 5;
princess.Species = “Poodle”
princess.Name = “Princess”
Dog wolfy = new Dog();
wolfy.Age = 10;
wolfy.Species = “Husky”
wolfy.Name = “Wolfy”
List<Dog> dogs = new List<Dog>();
dogs.Add(max);
dogs.Add(spike);
dogs.Add(princess);
dogs.Add(wolfy);
Now I’d like to be able to sort a few different ways, and I can do this by providing an object that implements an IComparer interface of type Dog, like so:
public class DogAgeComparer : IComparer<Dog>
{
}
Now that I have my class, let’s implement the interface:
public class DogAgeComparer : IComparer<Dog>
{
#region IComparer<Dog> Members
public int Compare(Dog x, Dog y)
{
return x.Age.CompareTo(y.Age);
}
#endregion
}
Now that we have that, we can sort our list based on the dog’s age:
dogs.Sort(new DogAgeComparer());
This will sort the list in the appropriate order of age.
Similarly, we can use a different object for Name and have that available as well.
public class DogNameComparer : IComparer<Dog>
{
#region IComparer<Dog> Members
public int Compare(Dog x, Dog y)
{
return x.Name.CompareTo(y.Name);
}
#endregion
}
Now sort the list:
dogs.Sort(new DogNameComparer());
And there you have it! Quick and easy sorting of your objects.
Happy sorting!
Rob
Stack Reflections
If you haven’t noticed by my choice of presentation topics, I’m a big fan of Reflection. I like the flexibility and scalability it allows me to build into my applications. There are also some neat little tricks you can use with it, in conjunction with the stack trace, to better track your errors and debugging statements.
First of all, how would you like to be able to write a trace statement that shows your methods called without having to remember to code the method names? This can be accomplished by “walking the stack trace” during a method call and using the reflected method information from the stack to determine what method called your function. It works something like this:
I’m going to write a method called TraceMethodStart with no parameters. This method will load up the stack trace, walk the stack frame back one level, and then write out to Trace the method name and module name of the method that called the TraceMethodStart function.
public void TraceMethodStart()
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
string sMethod = “Unknown method”;
string sClass = “Unknown type”;
//make sure I have frames
if (currentStack.FrameCount > 0)
{
//get the method of the frame one up from me
System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
sMethod = oBase.Name;
sClass = oBase.DeclaringType.ToString();
}
if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write(“Starting: ” + sClass + ” ” + sMethod);
}
Now in my GetRob() function I do this:
namespace Sltc
{
public class Rob
{
public void GetRob()
{
TraceMethodStart();
}
}
}
And a “Starting: Sltc.Rob GetRob” will appear in our trace statements.
Now that’s useful. But it would be even more useful if we knew what was being passed to the function for parameters. Using the params keyword we can extend this function to accept a variable list of arguments so that we can call it from anywhere in our code and get passed any number of arguments. This will allow us to include the variables the function was given when it was called.
public void TraceMethodStart(params object[] oParms)
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
string sMethod = “Unknown method”;
string sClass = “Unknown type”;
//make sure I have frames
if (currentStack.FrameCount > 0)
{
//get the method of the frame one up from me
System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
sMethod = oBase.Name;
sClass = oBase.DeclaringType.ToString();
}
if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write(“Starting: ” + sClass + ” ” + sMethod);
foreach(object obj in oParms)
{
if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Trace.Write(“Parm: ” + oParm.ToString());
}
}
Now if you are in a method like so, you can do this:
function MyMethod(string s, int i)
{
TraceMethodStart(s, i);
}
Another handy thing you can do with this is to grab the cause for exceptions. A lot of times the stack trace is huge and it’s difficult to track down or even remember to write code to track where your exceptions are occuring. However, if you were to create your own exception, you could use a similar code sequence to grab the cause of the trouble:
public class SLTCException : System.Exception
{
private string _sClass = “Unknown”;
private string _sMethod = “Unknown”;
public SLTCException() : base()
{
System.Diagnostics.StackTrace currentStack = new System.Diagnostics.StackTrace();
if (currentStack.FrameCount > 0)
{
System.Reflection.MethodBase oBase = currentStack.GetFrame(1).GetMethod();
_sMethod = oBase.Name;
_sClass = oBase.DeclaringType.ToString();
}
}
}
Happy stacking!
Rob
.NET 2.0 Fun With Generics
So I spent this past weekend playing with Generics. For those of you who haven’t used them yet, they are a way to “generalize” your code while still maintaining type safety in .NET 2.0. You can do some very powerful things with them, and some of the native implementations can save you a ton of work.
First of all, there’s the List object in the new namespace System.Collections.Generic. This namespace is added by default to all of your class files when you create them in Visual Studio. This allows you to create lists of objects while telling the list the type of object you want to add, whereas in the past with Arrays or Dictionaries you had to check for the type or cast it correctly to make sure the list contained objects of the same type. For example:
List<int> oIntegers = new List<int>();
This will create a new list that will only allow ints to be added to it. In addition, you get type safety when enumerating or using for loops on the List:
foreach(int i in oIntegers)
{
i++;
}
In the past you would have had to cast this to int or check the type to make sure it would not break during the loop, but now because you’ve told the List what object type to expect, you have type safety. This also works when accessing an object by index:
int iFirst = oIntegers[0];
This will not require casting because the List already knows that any object within its collection will be an int. This is a great improvement over the collection objects in .NET 1.1.
That’s not the only thing you can do with Generics. You can also create classes that will contain and interact with various types of objects as well. One of the things that I’ve always been upset about is the inability to list the members of an Enum. If you’ve tried this you know what I mean…you want to be able to take an Enum and bind it to a dropdownlist or some other control so users can choose from each of the types and set it on an object. Well now, with a simple Generics based class that derives from List, you can do that:
public class EnumList<t> : List<t>
{
public EnumList()
{
try
{
string[] sNames = Enum.GetNames(typeof(t));
foreach (string sName in sNames)
{
base.Add((t)Enum.Parse(typeof(t), sName));
}
}
catch(Exception e)
{
throw new Exception("Not an enum type", e);
}
}
}
By placing a <t> behind your class definition (or “(Of T)” in VB.NET) you can hand your class a type to interact with, and use that to strongly type items added to your object. In this case, I am going to pass an Enum in as when creating the object, and in the body of the constructor, I will grab the GetNames() method off the Enum class and pass it the type of the object I was handed. Then I can loop through the items in the Enum and add it to the List I’ve derived from. Once that is done, I now have an object I can use for DataBinding to any bindable control, including DropDownLists on Web Forms.
Here’s how you would instantiate it:
public enum enLocomotion
{
Fly,
Walk,
Slither,
Swim
}
public class Animal
{
public List<enLocomotion> Locomotions
{
get
{
return new EnumList<enLocomotion>();
}
}
}
By telling the EnumList you wish it to use the enLocomotion,
the List that the class derives from will populate with
“Fly”, “Walk”, “Slither”, and “Swim” on the fly. This way,
if you add a new item to the Enum, it will automatically
get picked up without any code changes.
Animal oAnimal = new Animal();
this.DropDownList1.DataSource = oAnimal.Locomotions;
this.DropDownList1.DataBind();
Fly Walk Slither Swim
Have fun with Generics! I know I will.
Talk to you later,
Rob
