#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

#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);


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

            int i = 12;

        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;

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;
            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();

#654 – You Can’t Use an Anonymous Type Directly

An anonymous type is a temporary data type that is inferred based on the data that you include in an object initializer.  For example, the code below causes a class to be generated that contains three properties–Title, Year and Director.

var movie = new { Title = "Gladiator", Year=2000, Director = "Ridley Scott" };

When you declare an object with an anonymous type like this, the compiler automatically generates the type for you.  You can use ILDASM to look at the IL for this code and see the type.  It has a fairly cryptic name.

While the compiler creates a type to represent the object that you declared, you can’t reference this type explicitly in your code.

#653 – Projection Initializers

A projection initializer is a declaration for a member of an anonymous type that does not include a property name.

Here’s an example, where the members of the anonymous type are initialized using local variables.  The resulting property names in the anonymously-typed object match the variable names.

string title = "Seven Samurai";
string director = "Akira Kurosawa";
int year = 1956;

var movie = new { title, year, director };

You can also use properties of another object to initialize the anonymously-typed objects members.

            MovieInfo mi = new MovieInfo("Seven Samurai", "Akira Kurosawa", 1956);

            var movie = new { mi.Title, mi.Year, mi.Director };

#652 – Using Expressions and Variables in Anonymous Type Declarations

One way to declare an anonymous type is to specify the name of each property of the new type, along with the value of that property, expressed as a constant.

var movie = new { Title = "North By Northwest", Year = 1959, Director = "Alfred Hitchcock" };

When you declare an anonymously-typed object, you can use any expression as the value for a property.

// Note: GetFavMovie() returns a string
int birthYear = 1964;
var movie2 = new { Title = GetFavMovie(), Year = birthYear - 25, Director = movie.Director };

You can also leave off the named property and just include an named identifier representing a value.

        public static string Director { get; set; }
        private const int TheYear = 1956;

        static void Main()
            string aMovieTitle = "Seven Samurai";
            Program.Director = "Akira Kurosawa";

            var movie2 = new { aMovieTitle, TheYear, Program.Director };

The property names in the generated type will match the identifiers that you use.