in

Utah .NET User Group

Home of Utah's professional .NET developers.

C# Value Types

Last post 02-15-2008 11:30 AM by Fabio. 2 replies.
Page 1 of 1 (3 items)
Sort Posts: Previous Next
  • 02-14-2008 2:56 PM

    C# Value Types

    In C# there are both value types and reference types for some types. For example:

    Int32 == int
    Int64 == long int
    Int16 == short int

    Some value types don't have a direct reference equivalent, like:

    enum

    and

    struct

    although class would possibly be a good replacement for either one. My question is, in C# is there really ever a reason to use value types over reference types? I understand that the .Net JIT compiler (or whatever it's called, I apologize to those who are religious) compiles certain patterns to the best solution anyway, aside from what the programmer programs. This being the case, it doesn't seem right to me that a programmer would prefer to use value types over reference types, unless he or she had a VERY good reason. Does that make sense? Does it seem this way to anybody else?

    (Except in the case of String and string, where the type is pretty much the same except when using object.GetType(), where you must use String.)

    Nathan

  • 02-14-2008 7:23 PM In reply to

    • josh
    • Top 10 Contributor
    • Joined on 11-14-2006
    • Posts 9

    Re: C# Value Types

    Hey Nathan, good question I hadn't thought of those types like that.

    Lets look at a quick example in C#.
    using System;
    
    namespace TestCLIReferenceTypes
    {
        class Program
        {
            static void Main(string[ args)
            {
                Object obj = new Object();
                Int32 int32 = 100;
                uint rint = 200;
    
                for (; rint > 100 & int32 > 0; rint--, int32--)
                {
                    Console.WriteLine("{0}-{1}:{2}", rint, int32, obj);
                }
            }
        }
    }
    

    Now this sample is a bit contrived only because you have to actually use the variables or the compiler just optimizes them away. We simply have 3 variables; an Object, a System.Int32 and an int; one which we know is a reference type (Object).

    Lets see what the compiler does with our code; this is the IL that is created (I'll comment inline):
    .method private hidebysig static void Main(string[ args) cil managed
    {
        .entrypoint
        .maxstack 4
        .locals init (
            [0] object obj,               // We have 4 local variables
            [1] int32 int32,              // already this is looking interesting, they both turned out as "int32".
            [2] int32 rint,                 // lets look further to see if they are value types
            [3] bool CS$4$0000)
        L_0000: nop 
        L_0001: newobj instance void [mscorlib]System.Object::.ctor()  // here we see the reference type created by the newobj opcode
        L_0006: stloc.0                      // which calls the class constructor and puts a reference to the object on the stack
        L_0007: ldc.i4.s 100             // ah, the Int32 is loaded, but its value is directly loaded onto the stack instead of a reference
        L_0009: stloc.1 
        L_000a: ldc.i4 200                // same with our int
        L_000f: stloc.2 
        L_0010: br.s L_0034
        L_0012: nop 
        L_0013: ldstr "{0}-{1}:{2}"    // an aside: strings are special-cased in the CLI, though here it kind of looks like the value assignments above 
        L_0018: ldloc.2                     // they are always allocated in a string heap
        L_0019: box int32                 // another tell tale sign of value types, boxing
        L_001e: ldloc.1                     // the WriteLine takes object parameters so the ints need to be boxed
        L_001f: box int32
        L_0024: ldloc.0 
        L_0025: call void [mscorlib]System.Console::WriteLine(string, object, object, object)
        L_002a: nop 
    
    -- SNIP looping code --
    
        L_0042: ret 
    }
    

    Here is the reasoning for this. Microsoft defined the Common Language Infrastructure (CLI) and got it standardized by the ECMA (ECMA-335). The CLI is a specification where as the .NET framework is an implementation of the CLI. The subset of the CLI that describes what types can be used in a language is called the Common Language Specification (CLS). Microsoft's Common Language Runtime (CLR), the infrastructure that all .NET languages run ontop of, implements the CLS.

    In the CLR, the types that you see as System.Int32, System.Int64, etc. are implemented in mscorlib as outlined in the CLS. In fact, the C# specific type names such as int, short, object, and long are not CLS types at all, but aliases that the compiler maps at compile-time to the CLS types that the framework implements.

    Another interesting tidbit in that vien is that the CLR actually extends on the CLS and implements implements the capabilities for non-CLS types to be exposed in compilers, see the unsigned types in C# for example; uint, ushort, and ulong. These types are implemented in the CLR and exposed in C# even though they are not defined in the CLS. There are a couple consequences of using these types, the first being that your code would not be able to run on a runtime strictly implemented to the CLS. Another consequence is that a language that doesn't surface those types will not be able to interact with your code even if that language is running on the CLR.

    Hope that helps answer your question and explains a little more about how the compiler targets your code at the CLR.

    Have a good one,

    Josh
    Filed under: , , , , ,
  • 02-15-2008 11:30 AM In reply to

    • Fabio
    • Top 10 Contributor
      Male
    • Joined on 05-15-2006
    • West Jordan, UT
    • Posts 11

    Re: C# Value Types

    Nathan, int, long and short are not reference types. They are merely aliases or keywords that will be translated into System.Int32, System.Int64 and System.Int16 respectively. About your question, there are significant differences between reference types and value types, such as allocation, heap for reference types vs. context based allocation for value types (local variables are allocated on the stack). Casting is also hugely impacted by the Type you're using (reference or value), as boxing may occur with value types (which is a VERY important concept to understand). I would recommend reading on the subject (Essential .NET from Don Box and CLR via C# from Jeff Richter are great sources). Understanding the difference between reference and value types (and how they are handled by the runtime) is fundamental and will tremendously help you understand other concepts like boxing/unboxing, Nullable types, generics, etc. The short answer to your question is YES. There are circumstances where you'd benefit from using value types over reference types (for instance, value types don't carry the overhead reference types do with the object header), but you have to carefully examin those and the reading I recommended will cover those cases. Let me know if you have any specific questions I might be able to help with, but as I mentioned, this topic is broad enough that requires more than just one forum post or two so I'd really recommend reading up on it. I hope that helps. - Fabio
    Fabio Cavalcante
Page 1 of 1 (3 items)
Copyright © 2000-2007, Utah .NET User Group
Powered by Community Server (Commercial Edition), by Telligent Systems