Friday, May 29, 2009

Trim function in javascript

Trim function in javascript

One important function which we miss very much while working with string object in javascript is the trim function. Not anymore. If you are using ASP.NET you can very well make use of “ValidatorTrim” function to trim both leading and trailing spaces. E.g. is shown below.

var testString = '   Test trail    text    ';
//Below code removes spaces before and after the word.
testString = ValidatorTrim(testString);

In the above e.g. ValidatorTrim removes the leading and trailing spaces in the “   Test text  ” string and returns “Test Text” as the string. So whenever you need to trim spaces in javascript then go ahead and use “ValidatorTrim” function to trim spaces.

If you keep a breakpoint on the ValidatorTrim function and step into the function you can see the following code.

function ValidatorTrim(s) {
    var m = s.match(/^\s*(\S+(\s+\S+)*)\s*$/);
    return (m == null) ? "" : m[1];
}

One can see from the above code that Regular Expression is used to pick out the text without the trailing and leading spaces. People who are not ASP.NET developers can very well implement the same logic and can have their own javascript trim function.

Try to know more

Sandeep

Tuesday, May 26, 2009

Serialization in .NET - 2

In my previous blog we saw the basics of serialization and how types/objects can be serialized to Binary format. In this blog we will see how to serialize objects to XML.

Serializing objects to XML

Before we see the code to serialize objects to XML some things to keep in mind for serializing objects to XML is that the class must have a default constructor. If the class doesn’t have a default constructor then at runtime the following error will be thrown.

[So and So Class] cannot be serialized because it does not have a parameterless constructor.

Another point to keep in mind is that all public properties which needs to be serialized must have get and set methods implemented, else the following errors, when the property is read only or write only, will be thrown by the compiler at runtime.

InvalidOperationException with the following message will be thrown during serialization by the compiler if the property is declared read only (no set method defined) only.
Unable to generate a temporary class (result=1).error CS0200: Property or indexer 'Cars.Car.Color' cannot be assigned to -- it is read only

InvalidOperationException with a NullReferenceException as the inner exception will be thrown during serialization by the compiler if the property is write only (no get method defined) only.
InvalidOperationException message - "There was an error reflecting type 'Cars.Car'."
NullReferenceException message - "Object reference not set to an instance of an object."

The same Car class illustrated in the previous blog can be serialized into XML with the help of the below code.

using (System.IO.FileStream xmlFS = new System.IO.FileStream("car.xml", System.IO.FileMode.Create))
{
    Cars.Car car = new Cars.Car { Model = "BMW 7 Series", Color = "Red", NoOfDoors = 4 };
    System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(car.GetType());
    xmlSer.Serialize(xmlFS, car);
}

One thing to note here is that unlike Binary serialization only public properties and fields will be serialized. Private member variables will not be serialized. The serialized xml of the Car class is pasted below.

<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Color>Red</Color>
  <Model>BMW 7 Series</Model>
  <NoOfDoors>4</NoOfDoors>
  <Price>0</Price>
</Car>

One more thing to note with XML serialization is that the class which needs to be serialized need not have a Serializable attribute applied to it like the one we used in binary serialization. To control XML serialization one needs to use attributes which control xml serialization. Some attributes which I think may be of use are listed below.

XmlIgnore

If you want a public field or property not to be serialized then you can make use XmlIgnore attribute. This will prevent a particular public field or property from being serialized. The serialized XML and XmlIgnore attribute applied to Color property of the Car class is pasted below.

namespace Cars
{   
    public class Car
    {       
        private string cubicCentimeter;
        [System.Xml.Serialization.XmlIgnore]
        public string Color
        { get; set; }
        public string Model
        { get; set; }
        public int NoOfDoors
        { get; set; }       
        public int Price
        { get; set; }    
    }
}

Serialized XML output after applying the XmlIgnore attribute.

<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Model>BMW 7 Series</Model>
  <NoOfDoors>4</NoOfDoors>
  <Price>0</Price>
</Car>

From the above xml one can see that the xml is missing the Color node as the XmlIgnore attribute is applied on it.

XmlAttribute

With the XmlAttribute attribute you tell the serialization process to convert the property or field as a XML attribute rather than as a XML node which is the normal behavior. If you want to change the attribute name and don’t want it to be same as that of the property name, you can make use of the “AttributeName” property along with the XmlAttribute attribute. To provide a namespace to the xml attribute you can make use of the “Namespace” property. When you provide namespace it has abide by w3 guidelines. As a general practice we provide urls as namespace. If you want to provide the data type of the attribute again that can be specified with the help DataType property. Sample code is pasted below.

public class Car
{       
    private string cubicCentimeter;
    [System.Xml.Serialization.XmlIgnore]
    public string Color
    { get; set; }  
   [System.Xml.Serialization.XmlAttribute (AttributeName="CarModel")]
    public string Model
    { get; set; }
    public int NoOfDoors
    { get; set; }       
    public int Price
    { get; set; }    
}

Serialized Xml output.

<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CarModel="BMW 7 Series">
  <NoOfDoors>4</NoOfDoors>
  <Price>0</Price>
</Car>

From the above xml you can see with the XmlAttribute added the Model property of the Car class has been converted as an Xml Attribute (highlighted in maroon) with the attribute name as “CarModel”. The attribute name is not same as that of the property name the reason being we have specified a different name by making use of AttributeName property of the XmlAttribute attribute.

XmlElement

XmlElement can be used to control the xml element attributes. Using the XmlElement attribute on a public property/field will convert the property/field to a XML element. The properties which can be used with XmlElement are, ElementName, DataType, Form, IsNullable, Namespace, Order and Type.

With ElementName one can provide a Name to the element if you don’t want the XML element name to be same as that of the property/field name.

DataType will help you to specify the XML schema data type. Namespace will help you to provide namespaces to the XML element.

IsNullable specifies whether a XML element node should be generated if the property/field is null. If the IsNullable value is true an empty XML element with xsi:nil attribute set to true will be generated for properties/fields having null value else no XML element node will be generated. One thing to note here is that IsNullable cannot be used with value type properties/fields as value types cannot contain null as a value. If used along with value type the compiler will throw System.InvalidOperationException with the following message.

IsNullable may not be 'true' for value type System.BlahBlah.  Please consider using Nullable<System.BlahBlah> instead.

Form property of XmlElement will tell serializer to whether qualify the XML element with a namespace or not. The accepted values are System.Xml.Schema.XmlSchemaForm.None, System.Xml.Schema.XmlSchemaForm.Qualified and System.Xml.Schema.XmlSchemaForm.Unqualified. It is an error to use “Unqualified” value along with Namespace property in an XmlElement attribute i.e. one cannot use both Namespace and “System.Xml.Schema.XmlSchemaForm.Unqualified” as value for Form property,  If used the compiler will throw System.InvalidOperationException with the following error message.

//Form property wrongly used along with Namespace property
[System.Xml.Serialization.XmlElement(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Namespace = "http://sandblogaspnet.com")]
public string Model
{ get; set; }

Error thrown as part of the above mistake.
The Form property may not be 'Unqualified' when an explicit Namespace property is present.

Order property in XmlElement will allow you to tell the serializer the order in which the XML element have to be serialized. If Order is used with any one property/field it has to be used with all the properties/fields. If not used with all the properties/field the compiler will throw a “System.InvalidOperationException” with the following Inner exception message.

“Inconsistent sequencing: if used on one of the class's members, the 'Order' property is required on all particle-like members, please explicitly set 'Order' using XmlElement, XmlAnyElement or XmlArray custom attribute on class member ‘XYZ’.”

With Type you can specifies the type of the object. Sample code showing most of the properties of the XmlElement attribute are shown below.

namespace Cars
{   
    public class Car
    {       
        private string cubicCentimeter; 
       [System.Xml.Serialization.XmlElement(Order = 2, IsNullable=true)]
        public string Color
        { get; set; } 
       [System.Xml.Serialization.XmlElement(ElementName = "ModelName", Order=1, IsNullable=true, DataType = "string")]
        public string Model
        { get; set; } 
       [System.Xml.Serialization.XmlElement(Order = 3, Namespace = "http://sandblogaspnet.com", Form = System.Xml.Schema.XmlSchemaForm.Qualified)]
        public int NoOfDoors
        { get; set; }
        [System.Xml.Serialization.XmlElement(Order = 4)]
        public int Price
        { get; set; }    
    }
}

//Car Class Initialization code.

Cars.Car car = new Cars.Car { Model = "BMW 7 Series", NoOfDoors = 4 };

Above Car class’ Serialized xml output.

<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ModelName>BMW 7 Series</ModelName>
  <Color xsi:nil="true" />
  <NoOfDoors xmlns="http://sandblogaspnet.com">4</NoOfDoors>
  <Price>0</Price>
</Car>

One can see the serialized XML output of the Car class. An empty Color node with the xsi:nill attribute set to true because of the IsNullable attribute being set to true. Also notice the property Model being serialized as “ModelName” node because we have provided “ModelName” as the element name in the ElementName property of XmlElement attribute. Also you can notice an attribute called “xmlns” in ‘NoOfDoors” node added because of the Namespace property being used along with XmlElement attribute.

XmlRoot

XmlRoot attribute is used against a class, struct, enum etc to declare it as the root element of the Xml. The properties which can be used along with XmlRoot attribute are ElementName, DataType, IsNullable and Namespace. All these properties have been explained above. Sample code with the XmlRoot attribute applied along with the serialized XML is pasted below.

namespace Cars
{    
[System.Xml.Serialization.XmlRoot(ElementName="Car",
DataType="Cars.Car", IsNullable=true,
Namespace="http://Cars.Car")]
    public class Car
    {       
        private string cubicCentimeter; 
        [System.Xml.Serialization.XmlElement(Order =
2, IsNullable=true)]
        public string Color
        { get; set; } 
    [System.Xml.Serialization.XmlElement(ElementName
= "ModelName", Order=1, IsNullable=true, DataType =
"string")]
        public string Model
        { get; set; } 
      [System.Xml.Serialization.XmlElement(Order =
3, Namespace = "http://sandblogaspnet.com", Form =
System.Xml.Schema.XmlSchemaForm.Qualified)]
        public int NoOfDoors
        { get; set; }
        [System.Xml.Serialization.XmlElement(Order =
4)]
        public int Price
        { get; set; }    
    }
}

Serialized XML output for the above class.
<?xml version="1.0"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://Cars.Car">
  <ModelName>BMW 7 Series</ModelName>
  <Color xsi:nil="true" />
  <NoOfDoors xmlns="http://sandblogaspnet.com">4</NoOfDoors>
  <Price>0</Price>
</Car>

XmlArray

If you want to control the serialization of collections which implement IEnumerable interface you can use XmlArray attribute. The properties which can be used along with XmlArray are Namespace, ElementName, Form, IsNullable and Order. The explanation for each of these have been already discussed in this blog so we will skip that part.

XmlArrayItem

XmlArrayItem can be applied to any class which implements IEnumerable interface. The attribute is used to describe the individual members of the collection/array. For e.g. you have an ArrayList collection object in which you want to store objects derived from the Car class then you have to tell the serializer about the composition of the ArrayList collection using the XmlArrayItem attribute. For e.g. the Car class is inherited by another class named Ferrari then you have to explicitly tell the compiler that the collection can contain Car object as well as Ferrari object as shown below.

public class CarCollection
{
    [System.Xml.Serialization.XmlArrayItem(ElementName = "Car", Type = typeof(Car)), System.Xml.Serialization.XmlArrayItem(ElementName = "Ferrari", Type = typeof(Ferrari))]
        public System.Collections.ArrayList Cars
        { get; set; }
}

If the XmlArrayItem is not used then the following error will be thrown by the compiler while serializing the collection.

System.InvalidOperationException - “There was an error generating the XML document.”

Inner Exception: “System.InvalidoperationException” - “The type Cars.Ferrari was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.”

One thing to note here is that if you are storing multiple types in a collection you have to specify all the types using the XmlArrayItem attribute. Even each derived classes have to be specified, just by specifying the parent class will not help. If you specify only the parent class then you can store only the parent class, trying to store the derived classes will throw the above error. So each an every derived class which you are planning to add in the collection needs to be specified. If any user type is missed then you will get the above error. Also if you are using the collection object to store .NET primitive types then there is no need to make use of the XmlArrayItem attribute. If you are making use of XmlArrayItem attribute to describe the primitive types in the collection then only the primitive types mentioned using the XmlArrayItem can be stored. Attempting to store primitive types other than the ones specified in the XmlArrayItem will throw the following error.

System.InvalidOperationException - "There was an error generating the XML document."

Inner Exception: System.InvalidOperationException - "The type System.Double may not be used in this context."

The above error was thrown because I haven’t mentioned Double as one of the XmlArrayItem. Code is pasted below.

[System.Xml.Serialization.XmlArrayItem(Type = typeof(string)), System.Xml.Serialization.XmlArrayItem(Type = typeof(int))]
public System.Collections.ArrayList PrimitiveTypes
{ get; set; }

So when the “PrimitiveTypes” property having a double value was serialized the above exception was thrown. So if your planning to store primitive types in a collection then its better not to decorate the property using the XmlArrayItem attribute. If you do then make sure you specify all the possible data types.

XmlInclude

XmlInclude can be used with classes, stucts, methods, web methods and interfaces. Its somewhat similar to XmlArrayItem in that XmlInclude can be used to describe the derived classes which needs to be included in the class, struct, method or interface. The same CarCollection is modified with the XmlInclude attribute and the sample code is pasted below.

[System.Xml.Serialization.XmlInclude(typeof(Car)),
System.Xml.Serialization.XmlInclude(typeof(Ferrari)),
System.Xml.Serialization.XmlInclude(typeof(FerrariF500))]
public class CarCollection
{
    public System.Collections.ArrayList Cars
    { get; set; }
}

If all the derived classes are not specified in the XmlInclude attribute then the same errors will be thrown as in XmlArrayItem.

XmlEnum

Can be used to describe how Enum needs to be serialized. It has only one property named Name using which you can specify what should be the name of the particular Enum value. Sample code is pasted below.

public enum CarType
{
    [System.Xml.Serialization.XmlEnum(Name="CompactCar")]
    SmallCar,
    [System.Xml.Serialization.XmlEnum(Name = "CompactSedan")]
    CS,
    Sedan,
    SportsCar,
    Suv
}

The Car class with the CarType enum added as a property  and the serialized content of the car class is pasted below.

namespace Cars
{      
    [System.Xml.Serialization.XmlRoot(ElementName="Car", IsNullable=true )]
    public class Car
    {         
        System.Xml.Serialization.XmlElement(Order = 2, IsNullable=true)]
        public string Color
        { get; set; }
        [System.Xml.Serialization.XmlElement(ElementName = "ModelName", Order=1, IsNullable=true)]       
        public string Model
        { get; set; }
        [System.Xml.Serialization.XmlElement(Order = 3)]
        public int NoOfDoors
        { get; set; }       
        [System.Xml.Serialization.XmlElement(Order = 4)]
        public int Price
        {
            { get; set; }
        }       
        [System.Xml.Serialization.XmlAttribute(AttributeName="CarType")]
        public CarType Type
        { get; set; }
    }
}

// The class with the initial values
Cars.Car car = new Cars.Car { Model = "i20", NoOfDoors = 4, Color="Red", Type=Cars.CarType.SmallCar };


//Serialized XML for the above declared class.
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CarType="CompactCar">
  <ModelName>i20</ModelName>
  <Color>Red</Color>
  <NoOfDoors>4</NoOfDoors>
  <Price>0</Price>
</Car>

From the above class definition one can see the CarType enum is added as a property of the Car class. In the serialized XML one can see the CarType enum is serialized as an XML attribute because of the XmlAttribute applied on it in the Car class. Also note that the value of the CarType XML attribute is “CompactCar” instead “SmallCar”, this is because of the XmlEnum attribute applied in enum.

Deserializing XML

As serialization is simple deserialization is also simple. The below code shows how to deserialize an object from a xml. The above XML is used for the below deserialization.

using (System.IO.FileStream xmlFS = new System.IO.FileStream("car.xml", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
    System.Xml.Serialization.XmlSerializer xmlSerr = new System.Xml.Serialization.XmlSerializer(typeof(Cars.Car));
    Cars.Car car = (Cars.Car)xmlSerr.Deserialize(xmlFS);
}

The below screenshot shows the properties deserialized and all the properties assigned.

image

We have seen XML serialization and how xml serialization can be controlled using different attributes. Next we will see how to serialize objects to SOAP format and attributes to control the same, till then try to know more.

Sandeep

Tuesday, May 5, 2009

Serialization in .NET - 1

Recently while returning home from work my wife (another .NET developer) was murmuring something. On further poking she said that she has been assigned a task where she has to serialize and deserialize objects and she is afraid of serialization. What? Serialization is pretty easy, I replied back. So that’ small discussion is my motivation for writing this blog on serialization. In this and subsequent blog I will show how easy serialization is and also delve into the nitty gritties of serialization.

What is serialization?

Serialization is the process of converting an object into another format whereby the state of the object can be easily saved to a file, database or memory etc and can be recreated easily. Serialization is not only for saving the object to different medium but also for transmitting the serialized objects through the network.

Different types of serialization.

The different types of serialization are

  • Binary Serialization
  • XML Serialization
  • SOAP Serialization

Binary Serialization

Binary serialization is the process where you convert your .NET objects into byte stream. In binary serialization all the public, private, even those which are read only, members are serialized and converted into bytes. So when you want a complete conversion of your objects to bytes then one can make use of binary serialization.

XML Serialization

In XML serialization only the public properties and fields of the objects are converted into XML. The private members are not taken into consideration in XML serialization.

SOAP Serialization

Similar to XML serialization. When you serialize object to SOAP format it conforms to the SOAP specification.

Lets jump into it.

Lets see each of the above serialization one by one. We will first see binary serialization then XML serialization and finally SOAP serialization.

Suppose I have a Car class (oh no! not again, the same Car class) as shown below.

namespace Cars
{
    [Serializable]
    public class Car
    {
        private string cubicCentimeter;
        public string Color
        { get; set; }
        public string Model
        { get; set; }
        public int NoOfDoors
        { get; set; }
        public int Price
        { get; set; }
    }
}

We have seen and talked about the Car class n number of times in my other blogs so I will skip and move over, it is a very simple class with a private member variable and four public properties which are making use of Automatic Properties. Please note the Serializable attribute at the top of the class. The Seializable attribute has to be applied to any type which needs to be serialized into a binary form. If the attribute is missing from the type then the compiler will throw a “System.Runtime.Serialization.SerializationException” with the following mesage.

Type 'CLASS/TYPE NAME' in Assembly 'ASSEMBLY NAME, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable

The code to serialize the Car object into a Binary stream is as shown below.

BinaryFormatter binFor = new BinaryFormatter();
using (System.IO.FileStream fs = new System.IO.FileStream("CarObject", System.IO.FileMode.Create))
{
    Cars.Car car = new Cars.Car { Model = "BMW 7 Series", Color = "Red", NoOfDoors = 4 };
    binFor.Serialize(fs, car);               
}

In the above code we are making use of the BinaryFormatter class to serialize the Car class to a Binary stream. One can see I am making use of Object Initializers to initialize the Car object. Once the car object is initialized I am calling the Serialize method of BinaryFormatter class and passing the Car object along with the FileStream object as arguments. All the members of the Car objects are serialized and dumped into the FileStream object. Even the private variable “cubicCentimeter” of the Car class is serialized to the file stream object. The byte stream generated by the BinaryFormatter class for the Car class is pasted below.

   ÿÿÿÿ          JSerializationSample, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null   Cars.Car   cubicCentimeter<Color>k__BackingField<Model>
k__BackingField<NoOfDoors>k__BackingField<Price>
k__BackingField     Red   BMW 7 Series

One can see from the above stream that all the public properties along with their values have been serialized. Even the private member variable (highlighted in Red) has been serialized.

Isn’t serialization so easy?

Now if you mark the class with the Serializable attribute all the member variables are serialized. We have seen from the above byte stream that even the private variable is serialized and that is not an expected behavior. We won’t like our private variables to be serialized, so, to do that we can use the “NonSerialized” attribute. The modified code (highlighted in red) is shown below.

namespace Cars
{
    [Serializable]
    public class Car
    {
        [NonSerialized]
        private string cubicCentimeter;
        public string Color
        { get; set; }
        public string Model
        { get; set; }
        public int NoOfDoors
        { get; set; }       
        public int Price
        { get; set; }
        public string ClassName()
        {
            return this.GetType().ToString();
        }
    }
}

The serialized content with the NonSerialized attribute applied is pasted below.

   ÿÿÿÿ          JSerializationSample, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null   Cars.Car   <Color>k__BackingField<Model>k__BackingField<NoOfDoors>
k__BackingField<Price>k__BackingField        Red  
BMW 7 Series

If you compare the above serialized content with the previous one you can find out that the content is not having the private member variable “cubicCentimeter”.

One thing to note here is that the NonSerialized attribute can only be used with fields and cannot be used with public properties. If used the following compile time error will be thrown.

“Attribute 'NonSerialized' is not valid on this declaration type. It is only valid on 'field' declarations.”

So if you want to prevent your public properties from getting binary serialized then you cannot use Automatic Properties, instead you have to go with the good old ways of declaring properties where you declare a private member variable which will hold the value of the property and then use the NonSerialized attribute on that member variable or you can write custom serialization by implementing ISerializable interface which we will see in my subsequent blog. The sample code below shows how to restrict public property from getting serialized using the NonSerialized attribute on the member variable storing the property value.

namespace Cars
{
    [Serializable]
    public class Car
    {
        [NonSerialized]
        private string cubicCentimeter;
        public string Color
        { get; set; }
        public string Model
        { get; set; }
        public int NoOfDoors
        { get; set; }       
        [NonSerialized]
        private int price;
        public int Price
        {
            get
            {
                return price;
            }
            set
            {
                price = value;
            }
        }
        public string ClassName()
        {
            return this.GetType().ToString();
        }
    }
}

Now when the above class is serialized it will be devoid of the public property Price. The byte stream is pasted below

   ÿÿÿÿ          JSerializationSample, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null   Cars.Car   <Color>k__BackingField<Model>k__BackingField<NoOfDoors>
k__BackingField       Red   BMW 7 Series  

So using the NoSerilaized attribute we can control a particular member of a class from getting serialized.

Deserializing the object

Deserializing the object and restoring it to its previous state is also pretty easy. The below code shows how to deserialize the Car object from the binary file created from the above serialization code.

using (System.IO.FileStream fs = new System.IO.FileStream("CarObject", System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
    BinaryFormatter deSerialize = new BinaryFormatter();
        Cars.Car car = (Cars.Car)deSerialize.Deserialize(fs);
}

In the above code FileStream object is used to read the binary content from a file and then the DeSerialize method of BinaryFormatter is used to deserialize the object to its state before serialization. The below screenshot shows all the properties of the Car class being read from the binary file and assigned.

image

In the next blog we will see xml serialization and related stuffs. Till then try to know more.

Sandeep

Friday, May 1, 2009

Object initializers and Collection initializers- Features of C# 3.0 (Part - 4)

In my previous blog we saw some of the new features introduced in .NET 3.0 like Extension Methods, Automatic Properties and Implicitly Typed Variable. This blog we will see Object initializers and Collection initializers.

We all have worked with objects and properties. If you are a .NET developers then there is no escaping from these. Suppose you have a class named car with the following structure.

public class Car
{
    public string Color
    { get; set; }
    public string Model
    { get; set; }
    public int NoOfDoors
    { get; set; }
}

The Car class in the above code has three properties (properties are defined using Automatic Property) namely Color, Model and NoOfDoors. Now if you want to assign values to these properties then we would write something like this.

Car car = new Car();
car.Model = "Ferrari F430 Spider";
car.NoOfDoors = 2;
car.Color = "Ferrari Red";

In the above code, we are first declaring an object of type Car and assigning the properties of the object one by one. Wont it be nice to trim some lines of code from the above code? This can be achieved with the new C# 3.0’ object initializer feature. Using Object initializer you can rewrite your code something like this.

Car car = new Car { Model = "Ferrari F430 Spider", Color = "Ferrari Red", NoOfDoors = 1 };

As you can see from the above code, object initializer feature helps us to assign the public properties while creating the object without having to call the constructor. To assign the property one has to type the property name followed by the equal to sign and value to be assigned within the curly braces. Now what happens if you have overloaded constructors which take arguments and you want use them along with object intializers? Don’t worry, one can very well use the overloaded constructor along with object initializers as shown below.

//Overloaded Constructor of Car class
public Car(string theModel) { this.Model = theModel };

Code using overloaded constructor along with object initializers.

//Passing the value for Model property through the overloaded constructor.
Car car2 = new Car("Ferrari F430") { Color = "Ferrari Red", NoOfDoors = 2 };

From the above code one can see we are calling the overloaded constructor with the value which needs to be assigned to the Model property of the Car class. Object initializers can be used with public fields as well. An e.g. is shown below.

//Bike class having public fields.
public class Bike
{
    public string Color;       
    public int CubicCapacity;       
}

//Assigning values to public fields using object initializers.
Bike bike = new Bike () { Color = "Red", CubicCapacity = 300 };

One can see that while using object initializers along with Bike object I have made use of “()” i.e. constructor call. This syntax is optional, even without the brackets the code will work perfectly fine. One can make use of object initializers even with complex objects, say for e.g. you have a CarEngine property (which is of type Engine class) inside the car class, you can declare the Car object with Engine object as a nested object as shown below.

//Car class with a complex Engine object as one of the property.
public class Car
{
    public Car(){}
    //Overloaded Constructor of Car class
    public Car(string theModel) { this.Model = theModel; }
    public string Color { get; set; }
    public string Model { get; set; }
    public int NoOfDoors { get; set; }
    public Engine CarEngine { get; set; }
}
//Engine class.
public class Engine
{
    public int CubicCapacity  { get; set; }
    public int NoOfValves { get; set; }
    public int BHP { get; set; }
}

//Nested object declaration using object initializers
Car car2 = new Car("Ferrari F430") { Model = "test", Color = car.Color, NoOfDoors = car.NoOfDoors, CarEngine = new Engine { CubicCapacity = 4550, BHP = 250, NoOfValves = 12 } };

The above code shows the revised Car class with CarEngine as a property which is of Engine class type. In the last three lines we can see the Car object has been declared using object initializer feature with a nested Engine class.

Object Initializers with Anonymous types

Object initializers can be used with Anonymous types as well. I know I have promised in my previous blog that my next blog will be on Anonymous types, but, I thought before explaining Anonymous types it is worth that people should know object initializers. For the time being just understand as the name suggests anonymous types don’t have any type. The below code will give you an idea of what is Anonymous types.

//Declaring Anonymous type.
var Employee = new { FirstName = "Sandeep", LastName = "P.R", Dept = "Software Developement" };
//Writing the value of the Anonymous object property value to the console.
Console.WriteLine("Name: {0}\nDepartment: {1}", Employee.FirstName, Employee.Dept);

Object initializers combined with Anonymous types can be used to create runtime objects without any concrete type. The scenario where this can be efficiently used is when you have complex object with lots of properties and you want to just make use of only two or three properties. Creating an instance of such a complex object is pure waste of memory space so instead of that one can create an Anonymous object with the required property.

Collection Initializers

Till now we had a look at object initialization, wont it be good if we had similar thing in arrays. Guess what, with C# 3.0 arrays/collection objects can be initialized in the same way. Sample code is shown below.

List<string> name = new List<string>() { "Sandeep", "Microsoft", "Windows XP", "Windows Vista" };

System.Collections.ArrayList oddArray = new System.Collections.ArrayList { new Car { Model = "BMW 7 Series" }, new Car{Model="BMW 5 Series", Color="Black"} };

The same was not possible in the early versions of C#. In C# 3.0 the compiler does the extra work of generating the code necessary to add the elements to the collection. The IL code doing the extra work for the above code is pasted below.

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 3
    .locals init (
        [0] class [mscorlib]System.Collections.Generic.List`1<string> name,
        [1] class [mscorlib]System.Collections.ArrayList oddArray,
        [2] class [mscorlib]System.Collections.Generic.List`1<string> <>g__initLocal0,
        [3] class [mscorlib]System.Collections.ArrayList <>g__initLocal1,
        [4] class Blog_Using.Car <>g__initLocal2,
        [5] class Blog_Using.Car <>g__initLocal3)
    L_0000: nop
    L_0001: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
    L_0006: stloc.2
    L_0007: ldloc.2
    L_0008: ldstr "Sandeep"
    L_000d: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
    L_0012: nop
    L_0013: ldloc.2
    L_0014: ldstr "Microsoft"
    L_0019: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
    L_001e: nop
    L_001f: ldloc.2
    L_0020: ldstr "Windows XP"
    L_0025: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
    L_002a: nop
    L_002b: ldloc.2
    L_002c: ldstr "Windows Vista"
    L_0031: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
    L_0036: nop
    L_0037: ldloc.2
    L_0038: stloc.0
    L_0039: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
    L_003e: stloc.3
    L_003f: ldloc.3
    L_0040: newobj instance void Blog_Using.Car::.ctor()
    L_0045: stloc.s <>g__initLocal2
    L_0047: ldloc.s <>g__initLocal2
    L_0049: ldstr "BMW 7 Series"
    L_004e: callvirt instance void Blog_Using.Car::set_Model(string)
    L_0053: nop
    L_0054: ldloc.s <>g__initLocal2
    L_0056: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
    L_005b: pop
    L_005c: ldloc.3
    L_005d: newobj instance void Blog_Using.Car::.ctor()
    L_0062: stloc.s <>g__initLocal3
    L_0064: ldloc.s <>g__initLocal3
    L_0066: ldstr "BMW 5 Series"
    L_006b: callvirt instance void Blog_Using.Car::set_Model(string)
    L_0070: nop
    L_0071: ldloc.s <>g__initLocal3
    L_0073: ldstr "Black"
    L_0078: callvirt instance void Blog_Using.Car::set_Color(string)
    L_007d: nop
    L_007e: ldloc.s <>g__initLocal3
    L_0080: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
    L_0085: pop
    L_0086: ldloc.3
    L_0087: stloc.1
    L_0088: ret
}

If you carefully examine the above IL one can see the C# compiler has done the following extra work

  • Generated the code to call the constructor of the objects we have initialized using object intializer.
  • Generated the code to assign the properties.
  • Generated the code to add the object to the collection object.

So with this we can say, behind the scene the compiler is doing most of the hard work which we as developers use to do repeatedly and it was quite mundane. So with C# 3.0’ object initializer feature Microsoft has relieved developers from writing the same code again and again and given the onus of doing that to the good old compiler. Don’t you think that’ this a great think to do, as we developers have lot of other great stuff to do than to sit and write tons of code to just initialize objects and collections. So what are you waiting for, start making use of these new features and write terse code and don’t forget, always try to learn more.

Next blog anonymous types.

Sandeep.