Archive for May, 2006

As, Is, and the Art of Reflection

Sunday, May 28th, 2006

I’m sure that for all of us there have been times when we want to get the type of an object that we’re using, especially when dealing with abstract classes, interfaces, and inheritance. For this, there’s a right way and a wrong way to do things.

The first way to determine the type of an object instance is to use reflection. You may have heard that reflection causes significant overhead. This is no exception. Here’s an example.

public void Display(IList displayer)
{
if (displayer.GetType() == Type.GetType("System.Collections.ArrayList"))
{
return;
}
// Other processing...
}

It’s bad enough that we’re using reflection for this information (via the GetType() method of displayer), but also that we’re hardcoding the type of the class we’re interested in with “System.Collections.ArrayList.” This can be cleaned up to the following:

public void Display(IList displayer)
{
if (displayer.GetType() == typeof(System.Collections.ArrayList))
{
return;
}
// Other processing...
}

However, it’s still reflection. Instead of using this, consider using the is keyword, which in fact does not use reflection at all but a special MSIL statement which is pretty quick, as far as what I’ve heard.

public void Display(IList displayer)
{
if (displayer is System.Collections.ArrayList)
{
return;
}
// Other processing...
}

Another keyword that is often overlooked is the as keyword. This handles casting on reference types. Although I hope you haven’t, maybe you’ve seen something like this before:

DataSet ds;
try
{
ds = (DataSet)Request.Cache["ds"];
}
catch { }

You don’t even need a try/catch statement here; just use the as keyword! Not only will it handle times when it is impossible to cast to the requested type by setting the value to null, but it also uses the same MSIL instruction as is, so it’s pretty efficient. You can’t use these two keywords with value types because value types and reference types are handled differently in memory.

Here’s one last example:

public void Display(IList«IDisposable» list)
{
int count = list.Count;
for (int i = 0; i < count; ++i)
{
IDisposable item = list[i];
if (item is SqlConnection)
{
(item as SqlConnection).Open();
}
// Other processing...
}
}

Say you wanted to check if a particular item is a SqlConnection object, and if it is, open it. Remember how is and as do basically the exact same thing though? So in this previous block of code you have a double cast. Consider doing something like the following:

public void Display(IList«IDisposable» list)
{
int count = list.Count;
for (int i = 0; i < count; ++i)
{
IDisposable item = list[i];
SqlConnection cnn = item as SqlConnection;
if (cnn != null)
{
cnn.Open();
}
// Other processing...
}
}

Matt’s First Rule of Performance

Saturday, May 20th, 2006

All of us know a little bit about code for us to be on the RevNet Development Team, but sometimes it takes more than knowing what to do to accomplish something—like reading an XML file and sending an email from the information inside it, or inserting user input into a database—to do it “right.” I came across a concept from NU’s own Matt Curland the other day that looked something like this:

// Matt’s first rule of performance:
// 0 > 1 > 2

So what does that mean? The gist is that if you need to get a result from a property or method, and you need to manipulate that value in more than one place, it’s better to call it once than call it twice. But even so, it’s better not to call anything at all if you can help it.

An example of this in practice was what he was referring to at the time: (beware, ORM jargon approaching!) the Multiplicity property of a Role object. This RoleMultiplicity is a measure of how many times a unique value could go into a fact table representing the role’s opposite role on a binary fact type i.e. if I had the fact type “Person(ID) has PersonName()” with a uniqueness and mandatory role constraint on the side of the Person object, calling the Multiplicity property of the PersonName’s role would give me RoleMultiplicity.ExactlyOne (opposite role’s constraints signify this).

Little did I know that calling this property was an immensely expensive procedure. It has to get the fact type from the model by using VS2005’s “Store” (as its name implies, stores everything that would be on the diagram, and we have know idea how that’s done; could be something of O(n2) complexity; see how Algorithms comes into play?!), and then create a new collection based on the roles from the model. It thens checks the count of the collection which does a lot of other checks (F11 makes you sick), and then does another loop to check for what multiplicity that role actually has. Before investigating all of that for ourselves, this is what our code looked like:

Before the Rule - Notice the properties referenced multiple times.

After the Rule - Notice how things are pulled out.

So remember:
When in doubt, pull it out.