Refactoring: Magic Numbers

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Another type of refactoring patterns is the Magic Number pattern.

Magic numbers are numbers with special meaning and value that usually are not obvious, such as PI. They are really nasty when you need to reference the same number many times. If the number might ever change, making the change is a nightmare. Even if you don’t make a change, you have the difficulty of figuring out what is going on.

If you have a magic number into your code and you use it frequently, you can create a constant, name it after the meaning, and replace the number with it. Most languages support constants. There is no cost in performance and there is a great improvement in readability.

But, before you do this refactoring, you should always look for an alternative. Look at how the magic number is used. Often you can find a better way to use it. If the magic number is a type code, consider replace type code with a class. If the magic number is the length of an array, use anArray.length instead when you are looping through the array. Otherwise, you can go and create your constant.

For example, the following code converts between meters and feet, and it uses a magic number that’s the feet in one meter:

// C# Code

public static double ConvertMetersToFeet(double meters)
{
    return meters * 3.2808398950131233595800524934383;
}
public static double ConvertFeetToMeters(double feet)
{
    return feet / 3.2808398950131233595800524934383;
}
' VB.NET Code

Public Function ConvertMetersToFeet(meters As Double) As Double
    Return meters * 3.2808398950131233595800524934383
End Function

Public Function ConvertFeetToMeters(feet As Double) As Double
    Return feet / 3.2808398950131233595800524934383
End Function

So, we can refactor the code to be:

// C# Code

public const double MeterFeet = 3.2808398950131233595800524934383;

public static double ConvertMetersToFeet(double meters)
{
    return meters * MeterFeet;
}
public static double ConvertFeetToMeters(double feet)
{
    return feet / MeterFeet;
}
' VB.NET Code

Public Const MeterFeet As Double _
    = 3.2808398950131233595800524934383

Public Function ConvertMetersToFeet(meters As Double) As Double
    return meters * MeterFeet
End Function

Public Function ConvertFeetToMeters(feet As Double) As Double
    return feet / MeterFeet
End Function

The lesson quoted from the book “Refactoring: Improving the Design of Existing Code” by Martin Fowler. Code snippets by Just Like a Magic.

Programmatically Compress and Decompress Files

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

This lesson is very easy. This lesson focuses on how to compress and decompress files programmatically using .NET Framework and C# -or any language that supports .NET of course.

Currently .NET Framework supports two types of compression algorithms:

  • Deflate
    This is a very simple algorithm, used for simple compression and decompression operations. Don’t use this algorithm except if you intend to use compressed data only in your application because this algorithm is not compatible with any compression tool.
  • GZIP
    This algorithm uses internally the Deflate algorithm. This algorithm includes a cyclic redundancy check value for detecting data corruption. Also it’s compatible with most compression tools because it writes headers to the compressed file, so compression tools -like WinZip and WinRAR- can easily access the compressed file and decompress it as well. This algorithm also can be extended to use other algorithms internally other than Deflate.

For a complete GZIP reference see RFC 1952 (GZIP File Format Specification).

The most powerful compression tool now is WinRAR.

Fortunately, whether using Deflate or GZIP in .NET, code is the same; the only thing that needs to change is the class name.

Deflate and GZIP can be found in the namespace System.IO.Compression that resides on assembly System.dll. This namespace contains only three types, the two algorithms implementation classes DeflateStream and GZipStream -both inherit directly from System.IO.Stream class-, and an enumeration CompressionMode that defines the operation (compression or decompression).

Compressing a file

The code for compression is very simple:

Code snippets in this lesson rely on the fact that you added two using (Imports in VB) statements, System.IO and System.IO.Compression.

// C# Code

string fileToBeCompressed = "D:\My Great Word Document.doc";
string zipFilename = "D:\CompressedGreatDocument.zip";

using (FileStream target = new FileStream(zipFilename, FileMode.Create, FileAccess.Write))
using (GZipStream alg = new GZipStream(target, CompressionMode.Compress))
{
    byte[] data = File.ReadAllBytes(fileToBeCompressed);
    alg.Write(data, 0, data.Length);
    alg.Flush();
}

Code explanation:
If you are going to compress a file then you must specify the CompressionMode.Compress option, and also you must specify a Stream that will the data be written to.
After creating the class you can compress the data by using its Write() method.

If you intended to use the Deflate algorithm, just change the class name to DeflateStream.

Decompressing a file

The code that decompresses a compressed file is very similar:

// C# Code

string compressedFile = "D:\CompressedGreatDocument.zip";
string originalFileName = "D:\My Great Word Document.doc";

using (FileStream zipFile = new FileStream(compressedFile, FileMode.Open, FileAccess.Read))
using (FileStream originalFile = new FileStream(originalFileName, FileMode.Create, FileAccess.Write))
using (GZipStream alg = new GZipStream(zipFile, CompressionMode.Decompress))
{
    while (true)
    {
        // Reading 100bytes by 100bytes
        byte[] buffer = new byte[100];
        // The Read() method returns the number of bytes read
        int bytesRead = alg.Read(buffer, 0, buffer.Length);

        originalFile.Write(buffer, 0, returnedBytes);

        if (bytesRead != buffer.Length)
            break;
    }
}
' VB.NET Code

Dim compressedFile As String = "D:CompressedGreatDocument.zip"
Dim originalFileName As String = "D:My Great Word Document.doc"

Dim zipFile As New FileStream(compressedFile, FileMode.Open, FileAccess.Read)
Dim originalFile As New FileStream(originalFileName, FileMode.Create, FileAccess.Write)
Dim alg As New GZipStream(zipFile, CompressionMode.Decompress)

While (True)
    ' Reading 100bytes by 100bytes
    Dim buffer(100) As Byte

    ' The Read() method returns the number of bytes read
    Dim bytesRead As Integer = alg.Read(buffer, 0, buffer.Length)

    originalFile.Write(buffer, 0, bytesRead)

    If (bytesRead  buffer.Length) Then
        Exit While
    End If
End While

Code explanation:

First, we create a file stream to read the ZIP file, and then we created our algorithm class that encapsulates the file stream for decompressing it.

Then we created a file stream for the original file, for writing the decompressed data.
After that, we read the data compressed 100bytes after each other -you may prefer more- and write this data to the original file stream.

By encapsulating disposable objects into using statements you become assured that every object will be disposed in a certain point -end of the using statement- and no object will retain in memory.

Try it yourself

Develop a simple application that can be used to compress and decompress files.

This application can compress several files into one file and decompress them as well.

Besides algorithms classes you may use System.IO.BinaryWriter and System.IO.BinaryReader to get full control of how the file contents will be.

Enumerating SQL Server Instances

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Starting from version 2.0, .NET supports a mechanism to enumerate the SQL Server instances in the local network. This is done by System.Sql.SqlDataSourceEnumerator class that resides on the assembly System.Data.

This class is a implements the singleton pattern, means that you can not instantiate it, and only a single instances serves all, accessed via the static property Instance.

Using the GetDataSources method of SqlDataSourceEnumerator, you get a DataTable object that contains four columns, ServerName, InstanceName, IsCulstered, and Version (Clear names, right?)

The following code retrieves information about all visible SQL Server instances in the local network:

// C# Code

static void Main()
{
    DataTable table =
        SqlDataSourceEnumerator.Instance.GetDataSources();

    DisplayTable(table);
}

private static void DisplayTable(DataTable table)
{
    foreach (DataRow row in table.Rows)
    {
        foreach (DataColumn col in table.Columns)
            Console.WriteLine("{0} = {1}", col.ColumnName, row[col]);
        Console.WriteLine(new string(' ', 30));
    }
}
 ' VB.NET Code

Sub Main()
    Dim table As DataTable = SqlDataSourceEnumerator.Instance.GetDataSources()

    DisplayTable(table)
End Sub

Sub DisplayTable(ByVal table As DataTable)
    For Each row As DataRow In table.Rows
        For Each col As DataColumn In table.Columns
            Console.WriteLine("{0} = {1}", col.ColumnName, row(col))
            Console.WriteLine(New String(" "c, 30))
        Next
    Next
End Sub

If you have a firewall installed on your machine, you will be asked to give permissions to the application.

GetDataSources() demands the FullTrust permission set.

Due to the nature of the mechanism used by SqlDataSourceEnumerator to locate data sources on a network, the method will not always return a complete list of the available servers, and the list might not be the same on every call.

Working with SQL Server BLOB Data in .NET

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Code: Geming.Samples.Blob.zip

Binary Large Objects (BLOBs) are pieces of data that have -usually- exceptionally large size (such as pictures or audio tracks). These values stored in SQL Server in an image column.

Sometimes the term BLOB is also applied to large character data values, such as those stored in text or ntext columns.

Also you can store BLOB data in a binary column, but it doesn’t take larger than 8000 bytes. And image columns are more flexible.

Working with BLOB data is a bit strange because:

  1. You don’t know how much size will be the retrieved data.
  2. The data may be very large so we need to retrieve it in chunks.

Our example is fairly simple. This example stores files in a database (FileStore) and retrieves it by name. The example relies on a database that contains one table, MyFiles. And the table itself contains two columns one for filename (PK) and the other is an image column for the file itself.

Storing BLOB data

Storing BLOB data in a database is easiest part:

In order to run this code, you must add using statements to Sql.Data.SqlClient and System.IO.

// C# Code

static void StoreFile(string filename)
{
    SqlConnection connection = new SqlConnection
        ("Server=(local) ; " +
        "Initial Catalog = FileStore ; " +
        "Integrated Security = SSPI");

    SqlCommand command = new SqlCommand
        ("INSERT INTO MyFiles VALUES (@Filename, @Data)",
            connection);

    command.Parameters.AddWithValue("@Filename",
        Path.GetFileName(filename));
    command.Parameters.AddWithValue("@Data",
        File.ReadAllBytes(filename));

    connection.Open();

    command.ExecuteNonQuery();

    connection.Close();
}
' VB.NET Code

Sub StoreFile(ByVal filename As String)
    Dim connection As New SqlConnection( _
        "Server=(local) ; Initial Catalog = FileStore ; " & _
        "Integrated Security = SSPI")

    Dim command As New SqlCommand( _
        "INSERT INTO MyFiles VALUES " & _
        "(@Filename, @Data)", connection)

    command.Parameters.AddWithValue("@Filename", _
        Path.GetFileName(filename))
    command.Parameters.AddWithValue("@Data", _
        File.ReadAllBytes(filename))

    connection.Open()

    command.ExecuteNonQuery()

    connection.Close()
End Sub

Code explanation:
First, we created a connection to the SQL Server database. And then, we created the SqlCommand object that will hold the T-SQL Insert statement. After that, we filled the command parameters with required values. Finally, we executed the command.

Well, for avoiding SQL-Injection attacks, it’s recommended that you use parameters instead of hard-coding the argument. Moreover, you can’t represent binary values as strings.
Frankly, it’s recommended using stored procedures instead of coding the commands.

It’s highly recommended that you dispose disposable objects like SqlConnection and SqlCommand. Try encapsulating it in a using statement.

Retrieving BLOB data

Retrieving BLOB data is a bit complex than storing it. The following method demonstrates this:

// C# Code

static byte[] RetrieveFile(string filename)
{
    SqlConnection connection = new SqlConnection
        ("Server=(local) ; Initial Catalog = FileStore ; Integrated Security = SSPI");

    SqlCommand command = new SqlCommand
        ("SELECT * FROM MyFiles WHERE Filename=@Filename", connection);

    command.Parameters.AddWithValue("@Filename", filename);

    connection.Open();

    SqlDataReader reader = command.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);

    reader.Read();

    MemoryStream memory = new MemoryStream();

    long startIndex = 0;
    const int ChunkSize = 256;
    while (true)
    {
        byte[] buffer = new byte[ChunkSize];

        long retrievedBytes = reader.GetBytes(1, startIndex, buffer, 0, ChunkSize);

        memory.Write(buffer, 0, (int)retrievedBytes);

        startIndex += retrievedBytes;

        if (retrievedBytes != ChunkSize)
            break;
    }

    connection.Close();

    byte[] data = memory.ToArray();

    memory.Dispose();

    return data;
}
' VB.NET Code
Function RetrieveFile(ByVal filename As String) As Byte()
    Dim connection As New SqlConnection( _
        "Server=(local) ; Initial Catalog = FileStore ; " & _
        "Integrated Security = SSPI")

    Dim command As New SqlCommand( _
        "SELECT * FROM MyFiles " & _
        "WHERE Filename=@Filename", connection)

    command.Parameters.AddWithValue("@Filename", filename)

    connection.Open()

    Dim reader As SqlDataReader = command.ExecuteReader _
        (System.Data.CommandBehavior.SequentialAccess)

    reader.Read()

    Dim memory As New MemoryStream()

    Dim startIndex As Long = 0
    Const ChunkSize As Integer = 256
    While (True)
        Dim buffer(ChunkSize) As Byte

        Dim retrievedBytes As Long = _
            reader.GetBytes(1, startIndex, buffer, 0, ChunkSize)

        memory.Write(buffer, 0, CInt(retrievedBytes))

        startIndex += retrievedBytes

        If (retrievedBytes  ChunkSize) Then
            Exit While
        End If
    End While

    connection.Close()

    Dim data() As Byte = memory.ToArray()

    memory.Dispose()

    Return data
End Function

Code explanation:
After connecting to the database and writing our query, we executed the query by calling ExecuteReader() method of the command object to get read-only forward-only pointer to the retrieved rows.

By default, SqlDataReader reads entire rows -that can be gigabytes of data.- By specifying CommandBehavior.SequentialAccess, it reads the data sequentially in a given chunk size by calling the GetBytes() -or GetChars for BLOB textual data- method.

Calling Read() of the SqlDataReader objects advances the pointer to the next row which is the first single row -if found- in our example.

The GetBytes() method takes five arguments:

  1. The column index.
  2. The index of which to start reading.
  3. The buffer object that will keep current retrieved data.
  4. Index in buffer of which to begin writing t.
  5. The length (chunk size) of the data to retrieve.

It it worth mentioning that this method returns number of bytes retrieved. After calling this method we used a MemoryStream object to write all data retrieved to.

Finally, we retrieve data by calling MemoryStream’s ToArray() function. (I think the code is now clear)

It’s not recommended using MemoryStream if the data is very huge.

SqlConnection, SqlCommand, SqlDataReader, and MemoryStream are all disposable objects.
Because the MemoryStream object may contain the retrieved data it’s highly recommended that you dispose it as soon as possible.

For a complete example download the sample project FileStore.
This project uses a database for storing files and retrieving it.
This database contains only one table, its definition is as follows:

FileStore File Table Definition

For creating the database, the project also inculdes a SQL Query file that contains the commands for creating it. Simply execute the file.

Download Here

Programmatically Swapping Mouse Buttons

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Swapping mouse buttons means swapping the two buttons, making the right button acts like the left one and vice versa. This is done -for normal users of course- using the Mouse properties dialog in the control panel. See the next figure.

For we developers you need to do this programmatically, and this is done by a very very trivial -not a joke- Win32 API function, SwapMouseButton (resides on user32.dll). The syntax of the function -in C- is as follows:

BOOL SwapMouseButton(
    BOOL fSwap
    );

This function simply takes a single BOOL argument and returns a BOOL value too.

If fSwap is TRUE then the right mouse button will do the primary functions like the left button -by default- does, and the left button will do the secondary functions that the right button -by default- does.

If the function swapped the buttons, then it will return FALSE, otherwise TRUE.

BOOL can take one of values TRUE (non-zero) or FALSE (zero).

In .NET Framework, you need to write a wrapper to this API function and this wrapper is like this:

// C# Code
[DllImport("user32.dll")]
static extern bool SwapMouseButton(bool fSwap);
' VB.NET
Declare Auto Function SwapMouseButton Lib "user32.dll" _
    (ByVal fSwap As Boolean) As Boolean

The DllImport attribute defines the DLL that contains the function.

The MarshalAs attributes defines how .NET types will be mapped to Win32 types (this process called marshaling). We applied this attribute to the return value of the function and to the single argument of the function.

The static extern modifiers are required for any PInvoke function.

PInvoke stands for Platform Invokation. It’s the process of wrapping an API function to .NET code.

Marshaling is the process of creating a bridge between .NET types and unmanaged types.

For unmanaged BOOL, .NET makes the marshaling process automatically, so you can safely remove the MarshalAsAttribute attributes.

Now it’s the time for the code for calling the function.

// C# Code

public void MakeRightButtonPrimary()
{
    SwapMouseButton(true);
}

public void MakeLeftButtonPrimary()
{
    SwapMouseButton(false);
}
' VB.NET Code

Public Sub MakeRightButtonPrimary()
    SwapMouseButton(True)
End Sub

Public Sub MakeLeftButtonPrimary()
    SwapMouseButton(False)
End Sub

Retrieving Motherboard Serial Number using WMI

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

A simple way to get system information is through Windows Management Instrumentation (WMI).

WMI was firstly introduced part of Windows 2000. It’s designed to help your system, applications, and networks.

WMI has amazing design; It’s implemented like a large database that contains several tables and types. And you can query it using SQL statements (really!).

.NET Framework includes a various classes for dealing with WMI. These classes reside on assembly System.Management that you can reference it into your project.

Querying WMI is very simple. First, create a ManagementObjectSearcher object that will hold the SQL query. Then you execute the query by calling the Get() method of the ManagementObjectSearcher object, returns a collection of ManagementObject objects. These object looks like rows in a database that you can access its columns -PropertyData objects- and retrieve its values.

In WMI tables called classes, rows called objects, and columns called properties.

The following example demonstrates how to get Motherboard information like its name and serial number:

// C# Code

// First we create the ManagementObjectSearcher that
// will hold the query used.
// The class Win32_BaseBoard (you can say table)
// contains the Motherboard information.
// We are querying about the properties (columns)
// Product and SerialNumber.
// You can replace these properties by
// an asterisk (*) to get all properties (columns).
ManagementObjectSearcher searcher =
    new ManagementObjectSearcher
    ("SELECT Product, SerialNumber FROM Win32_BaseBoard");

// Executing the query...
// Because the machine has a single Motherborad,
// then a single object (row) returned.
ManagementObjectCollection information = searcher.Get();
foreach (ManagementObject obj in information)
{
    // Retrieving the properties (columns)
    // Writing column name then its value
    foreach (PropertyData data in obj.Properties)
        Console.WriteLine("{0} = {1}", data.Name, data.Value);
    Console.WriteLine();
}

// For typical use of disposable objects
// enclose it in a using statement instead.
searcher.Dispose();
' VB.NET Code

' First we create the ManagementObjectSearcher that
' will hold the query used.
' The class Win32_BaseBoard (you can say table)
' contains the Motherboard information.
' We are querying about the properties (columns)
' Product and SerialNumber.
' You can replace these properties by
' an asterisk (*) to get all properties (columns).
Dim searcher As New ManagementObjectSearcher _
    ("SELECT Product, SerialNumber FROM Win32_BaseBoard")

' Executing the query...
' Because the machine has a single Motherborad,
' then a single object (row) returned.
Dim information As ManagementObjectCollection = searcher.Get()
For Each obj As ManagementObject In information
' Retrieving the properties (columns)
' Writing column name then its value
    For Each data As PropertyData In obj.Properties
        Console.WriteLine("{0} = {1}", data.Name, data.Value)
    Next
    Console.WriteLine()
Next

' For typical use of disposable objects
' enclose it in a using statement instead.
searcher.Dispose()
' VB6
Set colProcessList = GetObject("Winmgmts:") _
    .ExecQuery("SELECT SerialNumber, Product FROM Win32_BaseBoard")

For Each objprocess In colProcessList
    MsgBox ("Serial Number=" & objprocess.SerialNumber)
    MsgBox ("Product=" & objprocess.Product)
Next

To read more about WMI and get lists of classes and features that it supports, see WMI Reference.

A long time ago, I used that mechanism to protect my application from copying it from a PC to another. The application asks the user for the serial number if he changed his PC (frankly, Motherboard). Did you validate? The serial number itself is an encrypted hash of the Motherboard serial number!

Microsoft Small Basic

Microsoft Small Basic

Small Basic is a project that’s aimed at bringing “fun” back to programming. By providing a small and easy to learn programming language in a friendly and inviting development environment, Small Basic makes programming a breeze. Ideal for kids and adults alike, Small Basic helps beginners take the first step into the wonderful world of programming.

  • Small Basic derives its inspiration from the original BASIC programming language, and is based on the Microsoft .NET platform. It is really small with just 15 keywords and uses minimal concepts to keep the barrier to entry as low as possible.
  • The Small Basic development environment is simple, yet provides powerful modern environment features like Intellisenseâ„¢ and instant context sensitive help.
  • Small Basic allows third-party libraries to be plugged in with ease, making it possible for the community to extend the experience in fun and interesting ways.

Go now and download Microsoft Small Basic 0.3.1 for Free:
http://www.microsoft.com/downloads/details.aspx?FamilyID=B006D58D-C2C7-44AD-936B-E7E2D7DE793E&displaylang=en

Also you may download Microsoft .NET Framework 3.5 SP1 as a reqirement for starting Microsoft Small Basic:
http://www.microsoft.com/downloads/details.aspx?FamilyId=AB99342F-5D1A-413D-8319-81DA479AB0D7&displaylang=en

Microsoft Small Basic Blog:
http://blogs.msdn.com/smallbasic/

Microsoft Small Basic is one of DevLabs projects. Checkout DevLabs projects:
http://msdn.microsoft.com/en-us/devlabs/dd125421.aspx

Microsoft Small Basic Snapshots:

Microsoft Small Basic Snapshot (0)
Microsoft Small Basic Snapshot (6) Microsoft Small Basic Snapshot (2) Microsoft Small Basic Snapshot (4)
Microsoft Small Basic Snapshot (3) Microsoft Small Basic Snapshot (5) Microsoft Small Basic Snapshot (1)

Working with Strings with Combining Characters

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Contents

Contents of this article:

  • Contents
  • Introduction
  • Writing Arabic Diacritics
  • Using the Character Map Application
  • Enumerating a String with Only Base Characters
  • Enumerating a String with Combining Characters
  • Comparing Strings
  • Try it out!

Introduction

In some languages, like Arabic and Hebrew, you combine some characters with combining characters based on the pronunciation of the word.

Combining characters are characters (like diacritics, etc.) that are combined with base characters to change the pronunciation of the word (sometimes called vocalization.)

Some examples of combining characters are diacritics:

Base Character Combining Character(s) Result
1
Combining a single character

Arabic Letter Teh
Arabic Letter Teh
0x062A

Arabic Damma
Arabic Damma
0x064F
Arabic Letter Teh + Damma.gif
Letter Teh + Damma
2
Combining two characters
Arabic Letter Teh
Arabic Letter Teh
0x062A

Arabic Shadda
Arabic Shadda
0x0651

Arabic Fathatan
Arabic Fathatan
0x064B

Arabic Letter Teh + Shadda + Fathatan
Letter Teh + Shadda + Fathatan

When you combine a character with another one then you end up with two characters. When you combine two characters with a base one you end up with 3 characters combined in one, and so on.

Writing Arabic diacritics

The following table summarizes up the Arabic diacritics and the keyboard shortcut for each character:

Unicode Representation Character Name Shortcut
0x064B Arabic Fathatan Fathatan Shift + W
0x064C Arabic Dammatan Dammatan Shift + R
0x064D Arabic Kasratan Kasratan Shift + S
0x064E Arabic Fatha Fatha Shift + Q
0x064F Arabic Damma Damma Shift + E
0x0650 Arabic Kasra Kasra Shift + A
0x0651 Arabic Shadda Shadda Shift + ~
0x0652 Arabic Sukun Sukun Shift + X

Using the Character Map Application

Microsoft Windows comes with an application that help you browsing the characters that a font supports. This application is called, Character Map.

You can access this application by typing charmap.exe into Run, or pressing Start->Programs->Accessories->System Tools->Character Map.

Character Map application

Enumerating a String with Base Characters

Now we are going to try an example. This example uses a simple word,Word Muhammad (Mohammad; the name of the Islam prophet.)

Word Muhammad Details

This word (with the diacritics) is consisted of 9 characters, sequentially as following:

  1. Meem
  2. Damma (a combining character combined with the previous Meem)
  3. Kashida
  4. Hah
  5. Meem
  6. Shadda (a combining character)
  7. Fatha (a combining character both Shadda and Fatha are combined with the Meem)
  8. Kashida
  9. Dal

After characters combined with their bases we end up with 6 characters, sequentially as following:

  1. Meem (have a Damma above)
  2. Kashida
  3. Hah
  4. Meem (have a Shadda and a Fatha above)
  5. Kashida
  6. Dal

The following code simply enumerates the string and displays a message box with each character along with its index:

// C#

string name = "مُـحمَّـد"
string result = String.Empty;

for (int i = 0; i < name.Length; i++)
result += String.Format("{0}t{1}b", i, name(i));

MessageBox.Show(result);

' VB.NET

Dim name As String = "مُـحمَّـد"
Dim result As String = String.Empty

For i As Integer = 0 To name.Length – 1
result &= String.Format("{0}{1}{2}{3}", i, vbTab, name(i), vbNewLine)
Next

MessageBox.Show(result)

What we get? When enumerating the string, we enumerate its base characters only.

Enumerating a String with Combining Characters

.NET Framework provides a way for enumerating strings with combining characters, it is via the TextElementEnumerator and StringInfo types (both reside in namespace System.Globalization.)

The following code demonstrates how you can enumerate a string along with its combining characters:

// C#

string name = "مُـحمَّـد";
string result = String.Empty;

TextElementEnumerator enumerator =
StringInfo.GetTextElementEnumerator(name);

while (enumerator.MoveNext())
result += String.Format("{0}t{1}b",
enumerator.ElementIndex, enumerator.Current);

MessageBox.Show(result);
' VB.NET

Dim name As String = "مُـحمَّـد"
Dim result As String = String.Empty

Dim enumerator As TextElementEnumerator = _
StringInfo.GetTextElementEnumerator(name)

While enumerator.MoveNext()
result &= String.Format("{0}{1}{2}{3}", _
enumerator.ElementIndex, vbTab, _
enumerator.Current, vbNewLine)
End While

MessageBox.Show(result)

Comparing Strings

Sometimes, you will be faced with a situation where you need to compare two identical strings differ only by their diacritics (combining characters) for instance. If you were to compare them using the common way (using String.Compare for instance) they would be different because of the combining characters.

To overcome this you will need to use a special overload of String.Compare method:

The Kashida, isn’t of the Arabic alphabets. It’s most likely be a space! So the option CompareOptions.IgnoreSymbols ignores it from comparison.

// C#

string name1 = "محمد";
string name2 = "مُـحمَّـد";

// 1st check
if (name1 == name2)
MessageBox.Show("Strings are identical");
else
MessageBox.Show("Strings are different!");

// 2nd check
if (String.Compare(name1, name2) == 0)
MessageBox.Show("Strings are identical");
else
MessageBox.Show("Strings are different!");

// 3rd
if (String.Compare(name1, name2,
System.Threading.Thread.CurrentThread.CurrentCulture,
CompareOptions.IgnoreSymbols) == 0)
MessageBox.Show("Strings are identical");
else
MessageBox.Show("Strings are different!");
' VB.NET

Dim name1 As String = "محمد"
Dim name2 As String = "مُـحمَّـد"

' 1st check
If (name1 = name2) Then
MessageBox.Show("Strings are identical")
Else
MessageBox.Show("Strings are different!")
End If

' 2nd check
If (String.Compare(name1, name2) = 0) Then
MessageBox.Show("Strings are identical")
Else
MessageBox.Show("Strings are different!")
End If

' 3rd check
If (String.Compare(name1, name2, _
System.Threading.Thread.CurrentThread.CurrentCulture, _
CompareOptions.IgnoreSymbols) = 0) Then
MessageBox.Show("Strings are identical")
Else
MessageBox.Show("Strings are different!")
End If