#661 – Every Object Has A ToString Method

Since every type inherits either directly or indirectly from System.Object, and System.Object has a ToString method, every object inherits a ToString method.

The ToString method is intended to return a string identifying or representing the object, i.e. that specific instance.  This is true for both value types and reference types.

For built-in types, ToString generally returns what you’d expect.  For example, for a System.Int32 (int), it returns the value of the integer.

For custom types, if you don’t override ToString and provide something more meaningful, ToString just returns a string representing the type of the object.

Dog kirby = new Dog("Kirby", 13);
Cow bessie = new Cow("Bessie");
int i = 12;
double d = 1.38e-23;
DayOfWeek bestDay = DayOfWeek.Saturday;
object o = new System.Object();
DateTime dt = new DateTime(1536, 5, 19);

// ToString can be called explicitly, or is called
// implicitly when passing object as string parameter
Console.WriteLine(kirby.ToString());   // Explicit
Console.WriteLine(bessie);             // Implicit
Console.WriteLine(i);
Console.WriteLine(d);
Console.WriteLine(bestDay);
Console.WriteLine(o);
Console.WriteLine(dt);

Advertisements

#660 – The typeof Operator Gets Information About a Type

You can use the typeof operator to get information about a particular type.  The operator returns an instance of the Type class, which you can then query to get info about the type.

typeof is a little different from the GetType method in System.Object.  typeof gets type information for a type, whereas GetType gets type information for an object’s type.

        static void Main()
        {
            Dog kirby = new Dog("Kirby", 13);
            DumpTypeInfoFor(kirby.GetType());

            DumpTypeInfoFor(typeof(Dog));
        }

        private static void DumpTypeInfoFor(Type t)
        {
            Console.WriteLine("Type = {0}", t);
            // etc
        }

#659 – Get Information About an Object’s Type

You can call the GetType method of System.Object on any object to get information about that object’s type.  Because every type in .NET inherits directly or indirectly from System.Object, every object will have access to the GetType method.

GetType returns an instance of a Type object, which can be queried to learn all about the type of the original object.

        static void Main()
        {
            Dog kirby = new Dog("Kirby", 13);
            DumpTypeInfoFor(kirby);

            int i = 12;
            DumpTypeInfoFor(i);
        }

        private static void DumpTypeInfoFor(object o)
        {
            Type t = o.GetType();

            Console.WriteLine("Type = {0}", t);
            Console.WriteLine("  Assembly = {0}", t.Assembly);
            Console.WriteLine("  BaseType = {0}", t.BaseType);
            Console.WriteLine("  FullName = {0}", t.FullName);
            Console.WriteLine("  IsClass = {0}", t.IsClass);
            Console.WriteLine("  IsValueType = {0}", t.IsValueType);

            Console.WriteLine("  Properties:");
            foreach (PropertyInfo pi in t.GetProperties())
                Console.WriteLine("    {0}", pi.Name);

            Console.WriteLine("  Methods:");
            foreach (MethodInfo mi in t.GetMethods())
                Console.WriteLine("    {0}", mi.Name);

            Console.WriteLine("  Events:");
            foreach (EventInfo ei in t.GetEvents())
                Console.WriteLine("    {0}", ei.Name);

            Console.WriteLine("  Interfaces:");
            foreach (Type ti in t.GetInterfaces())
                Console.WriteLine("    {0}", ti.Name);
        }

#658 – What Boxing and Unboxing Look Like in IL

Recall that your C# source code is compiled to a platform-neutral intermediate language called Common Intermediate Language.  You can view the IL for your application, after building the code, using the IL Disassembler tool.

If you look at the IL generated for code that boxes or unboxes a value, you’ll see unique CIL instructions for boxing (box) and unboxing (unbox).

Assume that you box an int value and then later unbox it.

int x = 12;

object o = x;    // Box

int y = (int)o;  // Unbox

If you build this code and look at the IL, you’ll see the box and unbox instructions.

#657 – Boxing Makes a Copy of An Object

When you pass a value-typed object to a function that accepts a parameter of type object, the value-typed object is boxed.  That is, it is copied into a temporary reference-typed object, which is actually passed into the function.  This boxing happens automatically.

If we look at an object that represents a boxed value type, we’ll see that its reported type is the value type.

        static void Test(object o)
        {
            Console.WriteLine(string.Format("Value = {0}, Type = {1}", o, o.GetType()));
        }

        static void Main()
        {
            int x = 12;
            Test(x);
        }



However, if we try changing the object within the method, the original int that was passed in is unaffected.

        static void Test(object o)
        {
            Console.WriteLine(string.Format("Value = {0}, Type = {1}", o, o.GetType()));
            o = 100;
        }

        static void Main()
        {
            int x = 12;
            Test(x);
            Console.WriteLine(string.Format("After call, x = {0}", x));
        }


The boxed object is passed into the function using value type semantics.

#656 – Nested Object Initializers

When using an object initializer to initialize the contents of an object, you can nest an inner object initializer to initialize an object that is referenced by a property of the outer object.

Assume that we have the following two classes:

    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int BirthYear { get; set; }
    }

    public class Movie
    {
        public string Title { get; set; }
        public int Year { get; set; }
        public Person Director { get; set; }
        public Person LeadActor { get; set; }
    }

We might then initialize a Movie object as follows:

            Movie aMovie = new Movie
            {
                Title = "Psycho",
                Year = 1960,
                Director = new Person { FirstName = "Alfred", LastName = "Hitchcock", BirthYear = 1899 },
                LeadActor = new Person { FirstName = "Anthony", LastName = "Perkins", BirthYear = 1932 }
            };

#655 – Initializing Only Some Properties with An Object Initializer

Using an object initializer, you can initialize an object by specifying values for its public properties, as long as the object’s type defines a parameterless constructor.

Movie aMovie = new Movie { Title = "Life Is Beautiful", Year = 1997, Director = "Roberto Benigni" };

Using this syntax, you can initialize any subset of the objects properties that you like. Any properties not initialized will take on default values.

            Movie movie = new Movie { Title = "Fight Club", Year = 1999 };
            Movie movie2 = new Movie { Year = 1972, Director = "Francis Ford Coppola" };
            Movie movie3 = new Movie { Title = "Taxi Driver" };


You could even use an empty object initializer, which would be equivalent to invoking the parameterless constructor directly.

            Movie movie4 = new Movie { };
            Movie movie5 = new Movie();