Archive for the ‘ csharp ’ Category

Dynamic Three Dimensional Arrays in C\C++\C#\Java


If you come from a Java or C# perspective and want to create a multi-dimensional array in C or C++, you’ll soon figure out that multi-dimensional array allocation in C\C++ is not as simple, plus you’ll have to worry about deallocation since there is no garbage collector to do the work for you. Below I’ll show four different sample codes showing how to work with a three dimensional array in Java, C#, C++ and C, respectively.

Java 3D Array

In Java, creating a 3-dimensional array is as simple as saying

int[][][] array3D = new int[x][y][z];

You can then access the elements of the 3-dimensional array at array3D[i][j][k].

Sample Code

public static void main(String[] args)
{
    //  Array 3 Dimensions
    int x = 4, y = 5, z = 6;

    //  Array Iterators
    int i, j, k;

    //  Allocate 3D Array
    int[][][] array3D = new int[x][y][z];

    //  Access array elements
    for (i = 0; i < x; i++)
    {
        System.out.println(i);

        for (j = 0; j < y; j++)
        {
            System.out.println();

            for (k = 0; k < z; k++)
            {
                array3D[i][j][k] = (i * y * z) + (j * z) + k;
                System.out.print("\t" + array3D[i][j][k]);
            }
        }

        System.out.println('\n');
    }
}

C# 3D Array

In C#, the concept is almost the same as in Java. However, C# makes the distinction between jagged and multi-dimensional arrays. Elements of a multi-dimensional array are stored in a contiguous block in memory while elements of a jagged array are not. Java arrays are actually jagged arrays, while C# supports both and allows you to choose which one you want based on the syntax of your code. Note that multi-dimensional arrays are better (in most cases) than jagged arrays, and that is considered a minus point for Java.

Using jagged arrays in C# is not as simple as in Java. It’s almost like the way we would implement it in C++.

int[][] jaggedArray = new int[2][];
jaggedArray[0] = new int[4];
jaggedArray[1] = new int[3];

However, multi-dimensional arrays in C# are very simply to use. You can create a 3 dimensional array as follows

int[,,] array3D = new int[x, y, z];

then access its elements at array3D[i][j][k].

Sample Code

static void Main(string[] args)
{
    //  Array 3 Dimensions
    int x = 4, y = 5, z = 6;

    //  Array Iterators
    int i, j, k;

    //  Allocate 3D Array
    int[,,] array3D = new int[x, y, z];

    //  Access array elements
    for (i = 0; i < x; i++)
    {
        Console.WriteLine(i);

        for (j = 0; j < y; j++)
        {
            Console.WriteLine();

            for (k = 0; k < z; k++)
            {
                array3D[i, j, k] = (i * y * z) + (j * z) + k;
                Console.Write("\t{0}", array3D[i, j, k]);
            }
        }

        Console.WriteLine('\n');
    }
}

C++ 3D Array

To create a multi-dimensional array in C++, we should change perspective a little bit and think of creating arrays that point to other arrays, which point to other arrays, and so on. For example, to create a 2x3x4 array in C++, we should imagine the implementation as follows:

For simplicity, we are doing the jagged implementation of the multi-dimensional array (address of array3d[0][1][0] is not directly after array3d[0][0][3] in memory representation above). In the next section, we will implement it in C the contiguous way. To allocate a jagged 2D array in C++, one can write the following (compare to C# jagged above):

int** jaggedArray = new int*[2];
jaggedArray[0] = new int[4];
jaggedArray[1] = new int[3];

The elements can be accessed as usual: jaggedArray[i][j]. The extra work we have to do in C++ is to explicitly deallocate the array.

delete[] jaggedArray[0];
delete[] jaggedArray[1];
delete[] jaggedArray;

See the code sample below to understand how we allocate and deallocate a 3 dimensional array in C++.

Sample Code

#include <iostream>

using namespace std;

void main()
{
    //  Array 3 Dimensions
    int x = 4, y = 5, z = 6;

    //  Array Iterators
    int i, j, k;

    //  Allocate 3D Array
    int ***array3D = new int**[x];

    for(i = 0; i < x; i++)
    {
        array3D[i] = new int*[y];

        for(j = 0; j < y; j++)
        {
            array3D[i][j] = new int[z];
        }
    }

    //  Access array elements
    for(i = 0; i < x; i++)
    {
        cout << i << endl;

        for(j = 0; j < y; j++)
        {
            cout << endl;

            for(k = 0; k < z; k++)
            {
                array3D[i][j][k] = (i * y * z) + (j * z) + k;
                cout << '\t' << array3D[i][j][k];
            }
        }

        cout << endl << endl;
    }

    //  Deallocate 3D array
    for(i = 0; i < x; i++)
    {
        for(j = 0; j < y; j++)
        {
            delete[] array3D[i][j];
        }

        delete[] array3D[i];
    }
    delete[] array3D;
}

C 3D Array

Implementing multi-dimensional arrays in C is very similar to C++, except that we use malloc()\free()  stdlib methods instead of the new\delete keywords. The memory representation below is the same, but we are going to focus in this section on making the elements of the 3 dimensional array contiguous.

To do so, we start by allocating space for all array elements in one call to malloc.

int *allElements = malloc(x * y * z * sizeof(int));

Next, we create the arrays of pointers, and point to the contiguous elements we’ve already allocated.

int ***array3D = malloc(x * sizeof(int **));
for(i = 0; i < x; i++)
{
    array3D[i] = malloc(y * sizeof(int *));

    for(j = 0; j < y; j++)
    {
        array3D[i][j] = allElements + (i * y * z) + (j * z);
    }
}

Note that if we wanted the same jagged implementation as in the C++ example above, we could ignore the allocation of allElements and change the line of code array3D[i][j] = allElements + (i * y * z) + (j * z); to array3D[i][j] = malloc(z * sizeof(int)). Below is a sample code for allocating, accessing and deallocating a 3 dimensional array in C.

#include <stdio.h>
#include <stdlib.h>

void main()
{
    //  Array 3 Dimensions
    int x = 4, y = 5, z = 6;

    //  Array Iterators
    int i, j, k;

    //  Allocate 3D Array
    int *allElements = malloc(x * y * z * sizeof(int));
    int ***array3D = malloc(x * sizeof(int **));

    for(i = 0; i < x; i++)
    {
        array3D[i] = malloc(y * sizeof(int *));

        for(j = 0; j < y; j++)
        {
            array3D[i][j] = allElements + (i * y * z) + (j * z);
        }
    }

    //  Access array elements
    for(i = 0; i < x; i++)
    {
        printf("%d\n", i);

        for(j = 0; j < y; j++)
        {
            printf("\n");

            for(k = 0; k < z; k++)
            {
                array3D[i][j][k] = (i * y * z) + (j * z) + k;
                printf("\t%d", array3D[i][j][k]);
            }
        }

        printf("\n\n");
    }

    //  Deallocate 3D array
    free(allElements);
    for(i = 0; i < x; i++)
    {
        free(array3D[i]);
    }
    free (array3D);
}

Source Code

Full source code for the above 4 samples is available here.

Xml Editor Control


If you have a Windows Forms application that involves Xml editing or viewing, you can use this control to save yourself the effort of formatting the Xml content. For now, only syntax highlighting is implemented. I expect to add more features in the future like spacing, grouping, intellisense, etc…

Usage

Simply add the files (XmlToken.cs, XmlTokenizer.cs, XmlEditor.cs, XmlEditor.designer.cs) to your project then drag and drop the XmlEditor control from the Toolbox into your Windows Form.

The XmlEditor control currently has three public properties. Use AllowXmlFormatting to enable or disable formatting on the Xml content in the editor. The ReadOnly property tells whether or not to allow the user to change the text. The Text property sets or gets the text of the Xml editor.

Here is how the control looks like when AllowXmlFormatting = true and ReadOnly = false (default values):

Implementation

To color the Xml string, we have to split it into multiple tokens, then color each token based on its type. I have identified the following token types (based on syntax highlighting behavior in Visual Studio 2008):

  • A “Value” is anything between double quotes
  • A “Comment” is anything that starts with <!– and ends with –> (or starts with <!– and is never closed with –>)
  • An “Element” is any letter or digit that falls between < and a space or >
  • An “Attribute” is any letter or digit that falls after a < followed by space and not closed by >
  • An “Escape” is anything that starts with & and ends with ; (For example &quote;)
  • A “SpecialChar” is any character that is not a letter or a digit
  • A “None” is anything else

The Tokenize() public static method of the XmlTokenizer class does the job of splitting a string into Xml tokens.

An XmlToken object is a representation of an Xml token with details about the exact text of that token, its location in the string and its type.

Here is the code in the XmlEditor control that does the syntax highlighting:

List<XmlToken> tokens = XmlTokenizer.Tokenize(xmlEditor.Text);

foreach (XmlToken token in tokens)
{
    xmlEditor.Select(token.Index, token.Text.Length);

    switch (token.Type)
    {
        case XmlTokenType.Attribute:
            xmlEditor.SelectionColor = Color.Red;
            break;
        case XmlTokenType.Comment:
            xmlEditor.SelectionColor = Color.DarkGreen;
            break;

        //  and so on for the other token types
    }
}

Download source and exe.

C# Windows Form is Busy


There are two very common ways of telling the user that your application is busy. One is to show a progress bar that gets updated based on the progress getting done, and another is to show the “Waiting” cursor while the application is doing work.

Waiting Cursor

To show the user the Waiting cursor while your program is busy, all you have to do is to set the current cursor to the Waiting cursor before your code runs, then set it back to an arrow after your code completes.

Cursor.Current = Cursors.WaitCursor;

//  Your Code

Cursor.Current = Cursors.Default;

Progress Bar

The progress bar is a more user-friendly solution, but in most cases showing the waiting cursor does the job. Here is the simplest way to use a progress bar:

int totalSteps = 10;
for (int i = 1; i <= totalSteps; i++)
{
    //  One chunk of your code

    int progress = i * 100 / totalSteps;
    blocksProgressBar.Value = progress;
}
blocksProgressBar.Value = 0;

Yes, it’s that easy to implement a progress bar that gets updated based on the work done by your app. However, while progress is shown, the user can’t interact with the UI or do any other operation (the UI thread is the single thread doing the work here). To get the multi-threaded behavior, the easiest way is to use a background worker process, as shown below:

So instead of putting your code in the event handler method, you will replace it with a call to start the worker process then move the code to the worker process events.

private void doButton_Click(object sender, EventArgs e)
{
    backgroundWorker.RunWorkerAsync();
}

The worker process will do its work in the DoWork event. To show progress, the code needs to be split into segments and the background worker ReportProgress method needs to be called whenever a segment of code is executed.

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    int totalSteps = 10;

    for (int i = 1; i <= totalSteps; i++)
    {
        //  One chunk of your code

        int progress = i * 100 / totalSteps;
        backgroundWorker.ReportProgress(progress);
    }
}

Whenever progress changes, we need to update the value of the progress bar.

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    blocksProgressBar.Value = e.ProgressPercentage;
}

When the worker process is done (progress = 100%), we reset the progress bar.

private void backgroundWorker_Completed(object sender, RunWorkerCompletedEventArgs e)
{
    blocksProgressBar.Value = 0;
}

Below is a Windows Form application that lets you try the concepts explained above, and also shows you how the Marquee progress bar works, which is shockingly harder than the more realistic single-threaded progress bar we’ve discussed above.

Download source and exe from here.

Sortable ListView


The Windows Forms ListView control doesn’t provide column sorting functionality. So if you click on a column in a ListView Details view, don’t expect the items to be sorted by the clicked column. To get this functionality, we’ll need to sort the items by the clicked column in the ListView ColumnClick event. I searched online for “Sortable ListView” and I found three MSDN articles talking about this: Sort ListView Column in Visual C#, Sorting ListView Items by Column Using Windows Forms, and How to: Sort ListView Items. None of those implementations takes into consideration the type of the column being sorted. That is, they all do string sorting. If you have dates and numbers in your list, then they’ll not be sorted properly. For example, number 2 will be considered greater than 11. Date time 9/9/1400 will be considered greater than 11/11/2020. Below is an implementation that takes into consideration string, DateTime, int and double types. It can be easily extended to handle more types.

  • Add the SortableListView control to your Windows Form
  • When adding columns to the SortableListView, set the Tag attribute to the type of the column.
sortableListView.Columns.Add("String Field").Tag = typeof(string);
sortableListView.Columns.Add("DateTime Field").Tag = typeof(DateTime);
sortableListView.Columns.Add("Int Field").Tag = typeof(int);
sortableListView.Columns.Add("Double Field").Tag = typeof(double);
  • Now, you can add the items as usual.

For example, the below list is sorted by the DateTime field.

Sortable ListView

Sortable ListView

 Click on the above image to download the SortableListView control.

PropertGrid Collection Events


You are using the PropertyGrid control to allow the user to edit the properties of an object at run-time from the UI. This works great and is in fact very reliable since this is the same control used by Visual Studio to display the properties of controls. Now that you are letting the user update the object directly, you’d like to get a PropertyValueChanged event whenever the user changes a property, so you can respond to the user’s action. You’ll be able to do that by adding a PropertValueChanged event to the PropertyGrid, which will get triggered every time a property is changed, unless the property is a collection. So if you have a collection inside the property grid selected object and you’d like to be notified when a property changes in that collection or when an item is added\removed, there is no way to do so with the OOB Microsoft PropertyGrid control. Clearly, the reason why the PropertyValueChanged event is not triggered when a collection is changed is because the reference to the collection object is still the same.

In order to be notified when a property changes inside a collection, follow instructions on this blog. You’ll find this very helpful. However, this solution can’t help you if you’d like to be notified when an item is removed from the collection or when it is added without any of its properties changed. A more generic solution I found was to get a notification when the collection form is closed. This way, I wouldn’t have to worry too much about the steps the user is taking in the collection editor. When the collection form is closed, I get notified and act on the collection object based on its current state.

Solution

First, add a reference to System.Design dll in your Visual Studio project. Create the following class, which represents a collection editor that triggers a MyFormClosed event when the collection editor form is closed.

using System;
using System.ComponentModel.Design;
using System.Windows.Forms;

public class MyCollectionEditor : CollectionEditor
{
    public delegate void MyFormClosedEventHandler(object sender,
                                        FormClosedEventArgs e);

    public static event MyFormClosedEventHandler MyFormClosed;

    public MyCollectionEditor(Type type) : base(type) { }
    protected override CollectionForm CreateCollectionForm()
    {
        CollectionForm collectionForm = base.CreateCollectionForm();
        collectionForm.FormClosed += new FormClosedEventHandler(collection_FormClosed);
        return collectionForm;
    }

    void collection_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (MyFormClosed != null)
        {
            MyFormClosed(this, e);
        }
    }
}

To use the above collection editor for the property grid, you can simply add the following attribute above the collection Property of the object which you set to propertGrid.SelectedObject.

[Editor(typeof(MyCollectionEditor), typeof(UITypeEditor))]

The final part is to create our custom FormClosed event handler and bind it to our custom collection editor as follows:

public MyForm()
{
    InitializeComponent();

    //  Make the property grid listen to collection properties changes
    MyCollectionEditor.MyFormClosed += new MyCollectionEditor.MyFormClosedEventHandler
                                        (propertyGrid_CollectionFormClosed);
}

private void propertyGrid_CollectionFormClosed(object s, FormClosedEventArgs e)
{
    //  Code to run when collection form is closed
}

Xml Serialization – Tips & Tricks


Let’s say we have an XSD representing a library with a list of books and employees in it. 

<?xml version="1.0" encoding="utf-8"?>

<xsd:schema id="Lib"
           targetNamespace="http://schemas.ali.com/lib/"
           elementFormDefault="qualified"
           xmlns="http://schemas.ali.com/lib/"
           xmlns:mstns="http://schemas.ali.com/lib/"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           version="1.0"
           attributeFormDefault="unqualified">

  <xsd:element name="Library" type="LibraryType" />

  <xsd:complexType name="LibraryType">
    <xsd:all>
      <xsd:element name="Books" type="BooksType" minOccurs="0" maxOccurs="1" />
      <xsd:element name="Employees" type="EmployeesType" minOccurs="0" maxOccurs="1" />
    </xsd:all>
  </xsd:complexType>

  <xsd:complexType name="BooksType">
    <xsd:sequence minOccurs="0" maxOccurs="unbounded">
      <xsd:element name="Book" type="BookType" />
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="EmployeesType">
    <xsd:sequence minOccurs="0" maxOccurs="unbounded">
      <xsd:element name="Employee" type="EmployeeType" />
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="BookType">
    <xsd:attribute name="Title" type="xsd:string" use="required" />
    <xsd:attribute name="Author" type="xsd:string" use="optional" />
  </xsd:complexType>

  <xsd:complexType name="EmployeeType">
    <xsd:attribute name="Name" type="xsd:string" use="required" />
  </xsd:complexType>

</xsd:schema>

Here is a sample Xml using this XSD: 

<?xml version="1.0" encoding="utf-8" ?>

<Library xmlns="http://schemas.ali.com/lib/">
  <Books>
    <Book Title="Book 1" Author="Ali"/>
    <Book Title="Book 2" Author="Sara"/>
  </Books>
  <Employees>
    <Employee Name="Ali"/>
    <Employee Name="Sara"/>
  </Employees>
</Library>

Tip 1 – Generating Code from XSD 

We’d like to have an object representation of this Xml. Thus, we’ll use the Xml Schema Definition tool to generate .Net C# code from the XSD, as follows: 

  • Start Visual Studio Command Prompt
  • Run this command: xsd “path to XSD file” -language:CS /classes /outputdir:”path to output directory”

As a result, a .cs file will be generated and copied to the output directory. Take a look at the file GeneratedLibrary.cs

Tip 2 – Using List<T> instead of array 

The <Books> and <Employees> elements are generated as arrays. So I would like to change those arrays to List<T> objects to make it easier to add items to them instead of having to worry about the size of the array and expanding it. Take a look at the modified class LibraryWithLists.cs. However, this is still not good enough because if I want to create a library with one book, I’ll have to write the following code: 

LibraryType library = new LibraryType();
library.Books = new BooksType();
library.Books.Book = new List<BookType>();
BookType newBook = new BookType();
newBook.Title = "Book 1";
newBook.Author = "Author 1";
library.Books.Book.Add(newBook);

But that doesn’t seem neat enough. I want to write something like: 

LibraryType library = new LibraryType();
library.Books = new List<BookType>();
BookType newBook = new BookType();
newBook.Title = "Book 1";
newBook.Author = "Author 1";
library.Books.Add(newBook);

Thus, I’ll need to get rid of the class BooksType and change it in the declaration from “private BooksType booksField;” to “private List<BookType> booksField;”. However, making that change only is not enough. We need to tell the serializer that the new property is an XmlArrayItem and not an XmlElement. Take a look at the resulting code in Library.cs.  

Tip 3 – Serializing Object to Xml 

Now, we should be able to write code and generate Xml from the object created. For example, writing the code below 

//  Create a library
LibraryType library = new LibraryType();

//  Create Books tag
library.Books = new List<BookType>();

//  Add 5 books to the library
for (int i = 1; i <= 5; i++)
{
    BookType book = new BookType();
    book.Title = string.Format("Book {0}", i);
    book.Author = string.Format("Author {0}", i);
    library.Books.Add(book);
}

//  Create employees tag
library.Employees = new List<EmployeeType>();

//  Add 3 employees to the library
for (int i = 1; i <= 3; i++)
{
    EmployeeType employee = new EmployeeType();
    employee.Name = string.Format("Book {0}", i);
    library.Employees.Add(employee);
}

//  Now that the object is created, serialize it and print out resulting Xml
XmlSerializer serializer = new XmlSerializer(typeof(LibraryType));
StringWriter sw = new StringWriter();
serializer.Serialize(sw, library);
Console.WriteLine("Object serialized to Xml:\n\n{0}", sw.ToString());

would result in the following Xml 

<?xml version="1.0" encoding="utf-16"?>
<Library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.ali.com/lib/">
  <Books>
    <BookType Title="Book 1" Author="Author 1" />
    <BookType Title="Book 2" Author="Author 2" />
    <BookType Title="Book 3" Author="Author 3" />
    <BookType Title="Book 4" Author="Author 4" />
    <BookType Title="Book 5" Author="Author 5" />
  </Books>
  <Employees>
    <EmployeeType Name="Book 1" />
    <EmployeeType Name="Book 2" />
    <EmployeeType Name="Book 3" />
  </Employees>
</Library>

Tip 4 – Serializing without Namespace 

If you look at the serialized Xml above, you’ll notice the extra xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance“,  xmlns:xsd=”http://www.w3.org/2001/XMLSchema”  and xmlns=”http://schemas.ali.com/lib/“. These namespaces are added by default. In my case, I only care about the  xmlns=”http://schemas.ali.com/lib/” which is the url for the XSD of my Xml file. To get rid of the above namespaces and keep the one referring to the XSD, we’ll need to pass our custom XmlSerializerNamespaces object to the Serialize() method. 

//  Create our own xml serializer namespace
//  Avoiding default xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
//  and xmlns:xsd="http://www.w3.org/2001/XMLSchema"
XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 

//  Add lib namespace with empty prefix
ns.Add("", "http://schemas.ali.com/lib/"); 

//  Now serialize by passing the XmlSerializerNamespaces object
//  as a parameter to the Serialize() method
XmlSerializer serializer = new XmlSerializer(typeof(LibraryType));
StringWriter sw = new StringWriter();
serializer.Serialize(sw, library, ns);
Console.WriteLine("Object serialized to Xml:\n\n{0}", sw.ToString());

If you want to get rid of the namespaces altogether, you can simply write ns.Add(“”, “”) instead of ns.Add(“”, “http://schemas.ali.com/lib/“)

Tip 5 – Changing Encoding

If you look at the generated Xml above, you’ll notice in the Xml declaration that the encoding is set to utf-16. To make this UTF8 encoding, we’ll need to change the Stream object settings before we do the serialization. To do this, replace the code below

StringWriter sw = new StringWriter();
serializer.Serialize(sw, library, ns);

with

//  Serialize the object to Xml with UTF8 encoding
MemoryStream ms = new MemoryStream();
XmlTextWriter xmlTextWriter = new XmlTextWriter(ms, Encoding.UTF8);
xmlTextWriter.Formatting = Formatting.Indented;
serializer.Serialize(xmlTextWriter, library, ns);
ms = (MemoryStream)xmlTextWriter.BaseStream;
string xml = Encoding.UTF8.GetString(ms.ToArray());

To make this more generic, we can create a static method that can do serialization with any encoding.

/// <summary>
/// Serializes the object to Xml based on encoding and name spaces.
/// </summary>
/// <param name="serializer"></param>
/// <param name="encoding"></param>
/// <param name="ns"></param>
/// <param name="objectToSerialize"></param>
/// <returns></returns>
public static string Serialize(XmlSerializer serializer,
                           Encoding encoding,
                           XmlSerializerNamespaces ns,
                           object objectToSerialize)
{
    MemoryStream ms = new MemoryStream();
    XmlTextWriter xmlTextWriter = new XmlTextWriter(ms, encoding);
    xmlTextWriter.Formatting = Formatting.Indented;
    serializer.Serialize(xmlTextWriter, objectToSerialize, ns);
    ms = (MemoryStream)xmlTextWriter.BaseStream;
    return encoding.GetString(ms.ToArray());
}

Now we can write something like the below

string xml = Serialize(serializer, Encoding.UTF8, ns, library);

Tip 6 – Removing Xml Declaration

Let’s say you want to completely remove the Xml Declarartion <?xml Version=”1.0″ Encoding=”utf-8″?> from your serialized Xml. You can do so neatly by using an XmlWriterSettings class and setting its OmitXmlDeclaration property to true. Here is how the above Serialize method would change to support this:

Thus, we can do something like the below to omit the Xml declaration

/// <summary>
/// Serializes the object to Xml based on encoding and name spaces.
/// </summary>
/// <param name="serializer">XmlSerializer object (passing as param to avoid creating one every time)</param>
/// <param name="encoding">The encoding of the serialized Xml</param>
/// <param name="ns">The namespaces to be used by the serializer</param>
/// <param name="omitDeclaration">Whether to omit Xml declarartion or not</param>
/// <param name="objectToSerialize">The object we want to serialize to Xml</param>
/// <returns></returns>
public static string Serialize(XmlSerializer serializer,
                               Encoding encoding,
                               XmlSerializerNamespaces ns,
                               bool omitDeclaration,
                               object objectToSerialize)
{
    MemoryStream ms = new MemoryStream();
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.OmitXmlDeclaration = omitDeclaration;
    settings.Encoding = encoding;
    XmlWriter writer = XmlWriter.Create(ms, settings);
    serializer.Serialize(writer, objectToSerialize, ns);
    return encoding.GetString(ms.ToArray()); ;
}

Tip 7 – Deserializing Xml to Object 

string xml = Serialize(serializer, Encoding.Default, ns, true, library);

This functionality is really cool. Load Xml into an object I can understand and easily interact with. For example, you’d write the following code to read the contents of Xml file “Sample1.xml” and convert it to object LibraryType.

//  Read the first Xml file
TextReader tr = new StreamReader("Sample1.xml");

//  Deserialize the Xml file into a LibraryType object
XmlSerializer serializer = new XmlSerializer(typeof(LibraryType));
LibraryType lib1 = (LibraryType)serializer.Deserialize(tr);

If you look at the object lib1 using the debugger, you’ll see that it’s properly loaded:

LibraryType Object
LibraryType Object

We can add a new book to this object and serialize it back to Xml using the following code

if (lib1.Books == null)
{
    lib1.Books = new List<BookType>();
}

BookType newBook = new BookType();
newBook.Title = "Book 3";
lib1.Books.Add(newBook);

//  Serialize back the library type object and output Xml
StringWriter sw = new StringWriter();
serializer.Serialize(sw, lib1);
Console.WriteLine("{0}:\n\n{1}", "Sample1.xml", sw.ToString());

The resulting Xml would look something like:

<?xml version="1.0" encoding="utf-16"?>
<Library xmlns="http://schemas.ali.com/lib/">
  <Books>
    <Book Title="Book 1" Author="Ali" />
    <Book Title="Book 2" Author="Sara" />
    <Book Title="Book 3" />
  </Books>
  <Employees>
    <Employee Name="Ali" />
    <Employee Name="Sara" />
  </Employees>
</Library>

Tip 8 – Resolving Empty Lists Issue

Now, let’s try the same deserialization code above, but on xml file “Sample2.xml” which has no <Employees> tag. When we deserialize xml into an object then serialize back into Xml, we get the following:

<?xml version="1.0" encoding="utf-16"?>
<Library xmlns="http://schemas.ali.com/lib/">
  <Books>
    <Book Title="Book 1" Author="Ali" />
    <Book Title="Book 2" Author="Sara" />
  </Books>
  <Employees />
</Library>

Notice the extra <Employees/> which we really didn’t intend to have in our Xml. I guess the reason for this issue is because XmlSerializer is initializing all List<T> variables in the object on deserialization (verified that by watching the object in the debugger after deserialization) and thus we’ll get this empty tag <Employees/> when we serialize back. To resolve this issue, there are two workarounds. The first approach is definitely better, but you might find the other approach helpful based on your needs.

Approach 1

Don’t bother with the empty lists. Just clean up their corresponding empty Xml tags on serialization. The method below takes a string represenation of the Xml and removes all empty tags.

/// <summary>
/// //////////Deletes empty Xml tags from the passed xml
/// </summary>
/// <param name="xml"></param>
/// <returns></returns>
public static string CleanEmptyTags(String xml)
{
    Regex regex = new Regex(@"(\s)*<(\w)*(\s)*/>");
    return regex.Replace(xml, string.Empty);
}

With the method above in mind, our Serialize method would change as follows:

public static string Serialize(XmlSerializer serializer,
                               Encoding encoding,
                               XmlSerializerNamespaces ns,
                               bool omitDeclaration,
                               object objectToSerialize)
{
    MemoryStream ms = new MemoryStream();
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = true;
    settings.OmitXmlDeclaration = omitDeclaration;
    settings.Encoding = encoding;
    XmlWriter writer = XmlWriter.Create(ms, settings);
    serializer.Serialize(writer, objectToSerialize, ns);
    string xml = encoding.GetString(ms.ToArray());
    xml = CleanEmptyTags(xml);
    return xml;
}

Approach 2

Call the deserialize as usual then set any empty instantiated lists (Count == 0) to null. Here is the static method and its helper method that does the job.


/// <summary>
/// Deserializes the passed Xml then deallocates any instantiated and empty lists.
/// </summary>
/// <param name="serializer"></param>
/// <param name="tr"></param>
/// <param name="objectNamespace"></param>
/// <returns></returns>
public static object Deserialize(XmlSerializer serializer, TextReader tr, string objectNamespace)
{
    //  Deserialize Xml into object
    object objectToReturn = serializer.Deserialize(tr);

    //  Clean up empty lists
    CleanUpEmptyLists(objectToReturn, objectNamespace);

    return objectToReturn;
}

/// <summary>
/// Sets any empty lists in the passed object to null. If the passed object itself is a list,
/// the method returns true of it's empty and false otherwise.
/// </summary>
/// <param name="o"></param>
/// <param name="objectNamespace"></param>
/// <returns></returns>
public static bool CleanUpEmptyLists(object o, string objectNamespace)
{
    //  Skip if the object is already null
    if (o == null)
    {
        return false;
    }

    //  Get the types of the object
    Type type = o.GetType();

    //  If this is an empty list, set it to null
    if (o is IList)
    {
        IList list = (IList)o;

        if (list.Count == 0)
        {
            return true;
        }
        else
        {
            foreach (object obj in list)
            {
                CleanUpEmptyLists(obj, objectNamespace);
            }
        }

        return false;
    }
    //  Ignore any objects that aren't in our namespace for perf reasons
    //  and to avoid getting errors on trying to get into every little detail
    else if (type.Namespace != objectNamespace)
    {
        return false;
    }

    //  Loop over all properties and handle them
    foreach (PropertyInfo property in type.GetProperties())
    {
        //  Get the property value and clean up any empty lists it contains
        object propertyValue = property.GetValue(o, null);
        if (CleanUpEmptyLists(propertyValue, objectNamespace))
        {
            property.SetValue(o, null, null);
        }
    }

    return false;
}

Using the above static method, you can now deserialize as follows:

//  Deserialize the Xml file into a LibraryType object
XmlSerializer serializer = new XmlSerializer(typeof(LibraryType));
LibraryType lib = (LibraryType)Deserialize(serializer, tr, typeof(LibraryType).Namespace);

If you know of a better solution, please let me know.

Source

Download full source code here. You can use it to try out the above tips one by one.

C# Regular Expression Helper


One component of an application I’m writing uses a lot of regular expressions. To be sure I was using the right regular expressions, I’ve created this simple tiny tool to help me learn and verify regular expressions against my input data. Nothing fancy, but it might help someone out there.

For example, it took me a little while trying to find the proper regular expression to match all comments (including those that are not closed) in an Xml file.

C# Regular Expression Helper

Download exe or source. I recommend using this tool with this cheat sheet. It’ll definitely speed up the learning curve.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: