هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.
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:
' 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
' 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.
هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.
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.
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.
هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.
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:
' 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.
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:
You don’t know how much size will be the retrieved data.
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.
' 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:
The column index.
The index of which to start reading.
The buffer object that will keep current retrieved data.
Index in buffer of which to begin writing t.
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:
For creating the database, the project also inculdes a SQL Query file that contains the commands for creating it. Simply execute the file.
هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.
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:
' 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
هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.
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!
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.
هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.
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
0x062A
Arabic Damma
0x064F
Letter Teh + Damma
2
Combining two characters
Arabic Letter Teh
0x062A
Arabic Shadda
0x0651
Arabic Fathatan
0x064B
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
Fathatan
Shift + W
0x064C
Dammatan
Shift + R
0x064D
Kasratan
Shift + S
0x064E
Fatha
Shift + Q
0x064F
Damma
Shift + E
0x0650
Kasra
Shift + A
0x0651
Shadda
Shift + ~
0x0652
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, (Mohammad; the name of the Islam prophet.)
This word (with the diacritics) is consisted of 9 characters, sequentially as following:
Meem
Damma (a combining character combined with the previous Meem)
Kashida
Hah
Meem
Shadda (a combining character)
Fatha (a combining character both Shadda and Fatha are combined with the Meem)
Kashida
Dal
After characters combined with their bases we end up with 6 characters, sequentially as following:
Meem (have a Damma above)
Kashida
Hah
Meem (have a Shadda and a Fatha above)
Kashida
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