Showing posts with label clr. Show all posts
Showing posts with label clr. Show all posts

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).

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.