Tuesday, December 5, 2006

Types: is operator, GetType method, and typeof keyword

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/types_is_operator_gettype_method_and_typeof_keyword.htm]

A common .Net question if "how do I determine if object x is of type y? For example, you may only want to perform certain operations on certain objects. Sometimes this can be solved by having that object implement an interface. But, there are other times you'll just need this ability. .Net provides easy ways to do this. Consider the code snippet below (notice that this is actually an MSTest unit test, but it's very easy to demonstrate quick code snippets because you can directly step into the code.

We notice a couple things:

  • is operator - shows if object x is of type y. If this condition is true, then you can cast the instance to the given type. This accounts for inheritance. For example, all types (such as System.Int32) inherit from System.Object.
  • GetType() method - a method on System.Object (and therefore available to all types) that returns the Type of the object. The Type class has a "FullName" property which returns a string of the name. Notice that you can tell the name of immediate type here, but it doesn't inheritance. For example, for an object on type "System.Int32"  the "is" keyword accounts for the current type (int) and the base type (object). GetType requires an instance and returns a type.
  • typeof keyword - Takes a Class an returns a Type (almost the inverse of typeof).

    [TestMethod]
    public void Type_Int32()
    {
      int i = 5;

      //Show 'is' operator
      Assert.IsTrue(i is int);
      Assert.IsTrue(i is object);
      Assert.IsFalse(i is double);

      //Show GetType and typeof
      Assert.IsTrue(i.GetType().FullName == "System.Int32");
      Assert.IsTrue(i.GetType() == typeof(System.Int32));

      //Declare Type instance
      Type t1 = null, t2 = null;
      t1 = i.GetType();
      t2 = typeof(System.Int32);

      Assert.IsTrue(t1 == t2);

    }

Notice that this same pattern can be applied to both value types (like a System.Int32) and reference types (like an XmlDocument):

    [TestMethod]
    public void Type_XmlDocument()
    {
      XmlDocument x = new XmlDocument();

      //Show 'is' operator
      Assert.IsTrue(x is XmlDocument);
      Assert.IsTrue(x is XmlNode);
      Assert.IsTrue(x is object);
      Assert.IsFalse(x is double);

      //Show GetType and typeof
      Assert.IsTrue(x.GetType().FullName == "System.Xml.XmlDocument");
      Assert.IsTrue(x.GetType() == typeof(System.Xml.XmlDocument));

      //Declare Type instance
      Type t1 = null, t2 = null;
      t1 = x.GetType();
      t2 = typeof(System.Xml.XmlDocument);

      Assert.IsTrue(t1 == t2);

    }

By using the is operator, GetType method, and typeof keyword, you can effectively manage type information and solve several problems in various ways.

Monday, December 4, 2006

Essential .Net Chapter 3: Type Basics

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/essential_net_chapter_3_type_basics.htm]

 

Chapter 3 of Don Box's book Essential .Net: the CLR explains the basic of types. While this is a common topic. Don has a clear way of explaining things. He does a good job of explaining the concepts of types in a way that transcends individual language syntax. This chapter connects a lot of dots, and makes a lot of sense once you've already been using an OOP language like C#. While most of this I've already seen before in other C# books, Don has a good way of explaining it:

Types - "A CLR type if a named, reusable abstraction." (pg 49) - I constantly have junior devs asking "What is a type?" I've heard several answers, like "A type (or form, or kind) of data", but I think Don's phrasing helps clarify the intent.

Sealed vs. Abstract - He explains how the class modifiers sealed (cannot be inherited) and abstract (must be inherited) are really opposites.

Const vs. Readonly - He discusses the difference between the const (made constant at compile time) and readonly (set in the type initializer at runtime, and then no longer editable). For example, consider this code snippet:

  class TypeDemo
  {
    public TypeDemo()
    {
      c2 = 456;
      c2 = DateTime.Now.Second;
    }

    public const int c1 = 123;
    public readonly int c2;

    private void MyMethod()
    {
      //This would cause a compile error:
      //c2 = 123;
    }
  }

Params - He discusses the params keyword in a method signature, which lets you pass in a variable amount of parameters into a method. The called-method receives these params as an array. Using Ildasm to view the code, one can see that the params keyword generates the System.ParamArrayAttribute.

    public static void DialEm(string message, params string[] numbers)    {      //Do stuff    }    public static void CallFred()    {      DialEm("Hi Fred!", "123", "456", "789");    }

Constructors - He explains about static vs. instance constructors. Looking at the IL, it's interesting to note that the static method has the name ".cctor", and the instance method has the name ".ctor" (only 1 c).

Interfaces - He points out that interfaces can strongly-type the context that an object should be used in. SO if you have objects AmericanPerson, CanadianPerson, and Turnip, you can have the first two objects implement the IPerson interface so that methods (at compile time) can uses those in a "person" context. By having an object implement multiple interfaces, you allow it to clearly be used in multiple contexts.

Overall, this chapter constantly transcends just the C# language and points to what the IL actually looks like. Constantly seeing the IL helps to fill in some gaps and see the significance of certain coding decisions.

Lastly, Don observes about the importance of types that "Developers spend most of their time defining new types in terms of existing types." (75). This is an interesting observation, and something that code generation is actively trying to address. For example, without codegen, a developer will spend a significant amount of time constructing objects that map to their database, like an "Employee" and "Customer" object. However, with codegen, the developer ideally just generates these objects based of of existing schema (such as a database or an xml file).

Sunday, December 3, 2006

What Flat Tires Can Teach You About Your Build Process

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/what_flat_tires_can_teach_you_about_your_build_process.htm]

While driving with my wife this weekend, we started hearing a strange bumping sound in our car. We didn't want to stop because it was the start of a Chicago winter, we were already late to our destination, and our 16-month old son was in the car. However, we quickly pulled over anyway - just as we started smelling burning rubber. Sure enough, we had a flat tire. After demonstrating my amazing car skills and impressing my wife (that's sarcasm - I have no car skills), we got the tire changed. We then drove back home and everything was okay.

Back in the comfort of our warm home, I started thinking how a flat tire reminded me of a broken build:

  • Both are dangerous if ignored: You will ruin your entire wheel and eventually car frame if you keep driving with a flat tire. Likewise, you will cripple your application with so many compile and test errors if you keep checking in code despite the build already being broken.
  • Both give you clear warning signs: A car with a flat makes an obvious sound, thumping feeling, and smells of burning rubber. A broken build (if you have a continuous integration system like Cruise Control) gives you clear emails about the exact build failure.
  • Both don't get fixed by ignoring the problem: A car tire doesn't magically get un-flat. A broken build doesn't magically get fixed.
  • Both require stopping what you're doing to fix the problem: In development, I constantly hear "but we're to busy to ". Just like fixing a flat requires you to stop the car (even if you're already late), fixing the build requires at least one developer to stop their features and check in a fix.
  • Both can be fixed with relatively little effort: A high-school kid can change a flat time in 10 minutes (i.e. it's not expensive or rocket science). Likewise, if you have continuous integration (and hence can see the exact code-checkin that broke the build, and the exact error that went wrong), it's usually very obvious and quick to make a fix - definitely much easier than if you wait and let the build errors grow.

Wednesday, November 29, 2006

Ildasm: Viewing attributes

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/ildasm_viewing_attributes.htm]

Yesterday I mentioned ILdasm to view the meta data on an assembly. One of the benefits of .Net is that it requires meta data for all assemblies. You can even create your own strongly-typed meta data via attributes. For example, both NUnit and MSTest use attributes to indicate that a certain method is a unit test. Because all the meta data is public, these external programs can use reflection to loop through all the methods in an assembly, and check which methods have which attributes.

These attributes show up in the IL. If you use Ildasm to view a method, you'll see which attributes it has. The IL snippet below has both the [TestMethod] attribute used by MSTest, and my own custom [Duration] attribute.

.method public hidebysig instance void  Duration_String_1() cil managed
{
  .custom instance void [Microsoft.VisualStudio.QualityTools.UnitTestFramework]Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute::.ctor() = ( 01 00 00 00 )
  .custom instance void TestDemo.Duration.DurationAttribute::.ctor(float64) = ( 01 00 7B 14 AE 47 E1 7A 84 3F 00 00 )             // ..{..G.z.?..
  // Code size       18 (0x12)
  .maxstack  2
  .locals init ([0] string s)
...
  IL_0011:  ret
} // end of method Strings::Duration_String_1

Of course, you'd probably never use Ildasm to read the attributes, but it's good to know that everything is consistent - i.e. meta data is public for any .Net assembly - it's not cryptic information only for debug more or something (like a *.pdb). So it makes sense that external programs like MSTest and NUnit can read these attributes.

Tuesday, November 28, 2006

Measuring the CLR, using ILdasm

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/measuring_the_clr_using_idasm.htm]

I've been looking more at the .Net CLR, i.e. how .Net really works under the hood. Because most of my work and hobbies are application development, it's easy to take the CLR for granted.

I've been reading Don Box's (with Chris Sells) Essential .Net Volume 1: The Common Language Runtime. I'll try to blog more about each chapter as I read it. Obviously given the popularity of both authors, it's a good book. Even though it's for .Net 1.0, it's still very practical.

It makes it much easier to understand something if you can observe and measure a cause and effect. Many devs I see don't try to understand the CLR because they can't measure much about it - such as how much memory some code takes, how fast the code runs, what happens when it gets compiled, etc... For example, many devs use try-catch to do business logic checks, and don't worry about performance because it "works fast enough on my machine."

I'm no CLR guru (you can see the official Microsoft CLR bloggers here), but I'll be blogging my adventure digging deeper into the CLR.

To kick it off, I started with Ildasm (view MSDN tutorial here). As every .Net book points out, .Net languages (like C# and VB.Net) get compiled into MSIL - Microsoft Intermediate Language - or just IL for short. This allows .Net to be language independent, because no matter what language you code in, it gets compiled to the same IL. Ildasm lets you see that compiled IL.

First, you can see the IL Specification here.

You can run Ildasm by opening the VS command prompt and just typing "ildasm". If you go to File > Open, you can browse for an assembly, load it, and then view its IL and meta information.

Here are some immediate benefits of what you can see with IL:

  1. Whether this is a debug or release assembly - the Debug version will have an extra line:
        // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute
  2. The meta data for the assembly (like company name)
  3. What other assemblies this one references.
  4. The actual IL. So, for example, you could see the number of boxing and unboxing operations by checking for the box and unbox IL commands.
  5. All the types and classes in the assembly.k

A super-version of IL, which can take an assembly and convert from the IL back to a .Net language is Lutz Roeder's Reflector. This is very useful for reverse engineering an assembly - even Microsoft's own system assemblies.

I'll blog more about this in my upcoming posts.

Monday, November 27, 2006

Logical puzzles

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/logical_puzzles.htm]

This is a cool website: http://www.techinterview.org/

It lists a bunch of logic puzzles that you'd likely see in a tech interview. Nice way to start the morning.

Sunday, November 19, 2006

Adding an Event to a User Control (Code Sample)

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/adding_an_event_to_a_user_control.htm]

I had talked about how to trigger an event from a UserControl.

This ability has many benefits, such as with refactoring. For example, suppose a UserControl is hosted on many different pages, and each page requires that the control have slightly different validation that incorporates values from the host page. One way to do this is to have the UserControl call a validation method on the host page.

Here's a code snippet you can download that shows how to have a UC call a method on its parent. The idea is to add an event member to the control, and hook it up with a delegate. (I had initially seen this technique from an article on MSDN several years ago).

This specific example has four files:

  • A UserControl - RecordNav.ascx and RecordNav.ascx.cs
  • A host page - HostRecordNav.aspx and HostRecordNav.aspx.cs

The UserControl contains an event "UpdateDate" and the host page adds a method to handle the event: RecordNav1_UpdateData.

    RecordNav1.UpdateData += new AspxDemo_Events_RecorNav.UpdateDataEventHandler(RecordNav1_UpdateData);