Tuesday, April 29, 2008

ReferencesManager 1.0.2 : Utility to check .NET assembly references.

    New build of ReferencesManager (v1.0.2) is released.

    The build include new command line switch:

-path=<customer path>

which allows to define additional folders to search referenced assemblies. For example:

ReferencesManager.exe Main.dll -path=D:\0;D:\1

Downloading ReferencesManager 1.0.2

Sources can be downloaded from "C# tips samples" project.

References:

Utility to check .NET assembly references

Sunday, April 27, 2008

C# checked and unchecked keywords.

C# arithmetic statements can be executed in checked or unchecked context. "Checked" context checks overflow and raises exception when a arithmetic overflow is detected.

Sample:

short x;
short y;
short z;

x = 10;
y = 20;
z = (short) (x + y);
Debug.Print("\nz = {0}, where x = {1}, y = {2} and z = (short) (x + y);\n", z, x, y);



outputChecked1



x = short.MaxValue;
y = short.MaxValue;
z = (short) (x + y);
Debug.Print("z = {0}, where x = {1}, y = {2} and z = (short) (x + y);\n", z, x, y);


outputChecked2



x = short.MaxValue;
y = short.MaxValue;
try
{
z = checked((short) (x + y));
Debug.Print("z = {0}, where x = {1}, y = {2}\n", z, x, y);
} catch (OverflowException)
{
Debug.Print("OverflowException ==> where x = {1}, y = {2} and z = checked((short) (x + y));\n", z, x, y);
}



outputChecked3



x = short.MaxValue;
y = short.MaxValue;
z = unchecked((short)(x + y));
Debug.Print("z = {0}, where x = {1}, y = {2} and z = unchecked((short)(x + y));\n", z, x, y);


outputChecked4



 



Reference:



checked (C# Reference)



unchecked (C# Reference)



Checked and Unchecked

Thursday, April 24, 2008

CSharp (c#) methods String.PadLeft(), String.PadRight().

    When we need to align output of strings we can use method String.PadLeft() or String.PadRight():

Sample:

string[] initialData = new string[] 
{"one", "two",
"three", "four", "five"};

Console.WriteLine("PadLeft sample");
foreach (string item in initialData)
{
string processedItem = item.PadLeft(10, '.');
Console.WriteLine("'{0}'", processedItem);
}

Console.WriteLine("PadRight sample");
foreach (string item in initialData)
{
string processedItem = item.PadRight(10, '.');
Console.WriteLine("'{0}'", processedItem);
}



Console output:



padConsole



Reference:



String.PadLeft Method



String.PadRight Method

Wednesday, April 23, 2008

CSharp (c#) method String.Join().

When we should create a string, which consists of array of strings with a separator usually we use a iterator (for, foreach).

For example,

string[] stringData = new string[] {"one", "two", "three"};
string outputContent1 = "";
foreach (string item in stringData)
{
outputContent1 += item + ";";
}
outputContent1 = outputContent1.Remove(outputContent1.Length - 1);
Debug.Print("output #1: {0}", outputContent1);



Now, we can use csharp (c#) method String.Join:



string outputContent2 = String.Join(";", stringData);
Debug.Print("output #2: {0}", outputContent2);



Output window:



joinOutput



Reference:



String.Join Method

Thursday, April 17, 2008

Power of Yield, Generics and Array in csharp (C#).

When it is necessary to process a array in normal order, we can use statement foreach.

But if we want to process the array in reverse order: from last array's element to first (0) element, we have a problem. Sure, we can use loop for (in reverse order) or call method Array.Reverse() and reverse elements of original array. Now we can suggest a additional way to get reverse processing of array with help of generics and yield.

Sample: process (output to console) int and string array in "normal" and "reverse" orders:

static void SampleReverese()
{
int[] intArray = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
string[] strArray = new string[] { "zero", "one", "two", "three", "four", "five" };

DisplayArray(intArray);
DisplayArray(Reverse(intArray));
DisplayArray(Reverse(strArray));
}
We can note, methods DisplayArray() and ReverseArray() can receive array of any elements.
It is implemented with help of c# generics.
Method Display():
static void DisplayArray<T>(IEnumerable<T> displayedArray)
{
Console.WriteLine();
foreach (T item in displayedArray)
{
Console.Write("{0} ", item);
}
}
More interesting how to implement method Reverse() without creation of new array or changing original array.
We use statement yield:


static IEnumerable<T> Reverse<T>(T[] originalArray)
{
for (int i = originalArray.Length - 1; i>=0; i--)
{
yield return originalArray[i];
}
}
Console:

reverseConsole

Reference:

yield (C# Reference)

Generics (C# Programming Guide)

Array.Reverse Method (Array)

foreach, in


Wednesday, April 16, 2008

How to remove leading and trailing characters from string in csharp (c#).

To remove leading and trailing characters from string in csharp (c#) we can use methods String.Trim(), String.TrimEnd() or String.TrimStart().

Samples:

originalLine = " message with space, ";
actualLine = originalLine.Trim();
DisplayMessage(originalLine, actualLine);


trimOutput1



originalLine = " message with space, ";
actualLine = originalLine.TrimEnd();
DisplayMessage(originalLine, actualLine);



trimOutput2



originalLine = " message with space, ";
actualLine = originalLine.TrimStart();
DisplayMessage(originalLine, actualLine);



trimOutput3



originalLine = " message with space, ";
actualLine = originalLine.Trim(new char[] { ' ', ',' });
DisplayMessage(originalLine, actualLine);


trimOutput4



Sometimes interesting to see implementation of C# methods.



So, let's see method String.Trim(Char[]):



// Removes a string of characters from the ends of this string. 
public String Trim(params char[] trimChars) {
if (null==trimChars || trimChars.Length == 0) {
trimChars=WhitespaceChars;
}
return TrimHelper(trimChars,TrimBoth);
}


and basic method TrimHelper():



private String TrimHelper(char[] trimChars, int trimType) { 
//end will point to the first non-trimmed character on the right
//start will point to the first non-trimmed character on the Left
int end = this.Length-1;
int start=0;

//Trim specified characters.
if (trimType !=TrimTail) {
for (start=0; start < this.Length; start++) {
int i = 0;
char ch = this[start];
for( i = 0; i < trimChars.Length; i++) {
if( trimChars[i] == ch) break;
}
if( i == trimChars.Length) { // the character is not white space
break;
}
}
}

if (trimType !=TrimHead) {
for (end= Length -1; end >= start; end--) {
int i = 0;
char ch = this[end];
for(i = 0; i < trimChars.Length; i++) {
if( trimChars[i] == ch) break;
}
if( i == trimChars.Length) { // the character is not white space
break;
}
}
}

//Create a new STRINGREF and initialize it from the range determined above.
int len = end -start + 1;
if (len == this.Length) {
// Don't allocate a new string is the trimmed string has not changed.
return this;
}
else {
if( len == 0) {
return String.Empty;
}
return InternalSubString(start, len, false);
}
}





References:



String.Trim Method

Split string to array of strings in csharp (c#).

    When we should divide a string to array of strings by a specific delimiters, we can use method String.Splt().

Samples:

string line = "name,id=1234,,description,user=Jon";



string[] lineItems = line.Split(new char[] { ',' });
DisplayOutput(line, lineItems);


splitOutput1



lineItems = line.Split(new char[] { ',', '=' });
DisplayOutput(line, lineItems);



splitOutput2



lineItems = line.Split(new char[] { ',', '=' }, 2);
DisplayOutput(line, lineItems);


splitOutput3



lineItems = line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
DisplayOutput(line, lineItems);



splitOutput4



lineItems = line.Split(new string[] { ",", "id=", "user="}, StringSplitOptions.RemoveEmptyEntries);
DisplayOutput(line, lineItems);



splitOutput5



References:



String.Split Method

Tuesday, April 15, 2008

Utility to check .NET assembly references

Sometimes, when a complex project (many source solutions, dlls, references) is built and run, then we receive a problem with references (here we don't speak about signed assemblies). For example, all dlls has a reference to basic .dll, but a specific .dll has a reference to obsolete version of the basic .dll.

Sample:

MainUtils has a reference to Utils1 (v2.0.0.0) and Utils2 (v2.0.0.0), but Utils2 (v2.0.0.0) has a reference to obsolete version of Utils1 (v1.0.0.0). See folders TestData4References in solution csharp-samples.

referenceDiagram

When a MainUtils will be run, then a error can be shown.

Utility ReferencesManager.exe helps to show all references and output list of all assemblies full names. This information helps to see same assemblies with different versions.

To start the utility it is necessary to type name of initial executable (or .dll) file:

ReferencesManager.exe MainUtils.exe > MainUtils.log

Content of MainUtils.log:

mainUtilsLog

Received log allows to find Utils1 with different versions 1.0.0.0 and 2.0.0.0 and Utils2, which references to Utils1 version 1.0.0.0.

Limitations of version 1.0.1:

  • The utility finds assemblies in GAC and in folder of initial assembly only.
  • The utility doesn't find referenced (in c# source project), but actually not used assemblies.
  • The utility doesn't output list of problematic assemblies.

Downloading ReferencesManager.exe.

References:

Reflector for .NET

Create and Share Flow Charts, Diagrams and More

Friday, April 11, 2008

Mainstream usage of yield (c#).

Let's review when csharp statement yield can be really useful. When we need process list (for example, display or calculate a parameter) of generated data we can use simple way and create array:

static public int[] PowerByArray(int number, int exponent)
{
int[] results = new int[exponent];
int result = 1;
for (int i = 0; i < exponent; i++)
{
result *= number;
results[i] = result;
}
return results;
}
call method PowerByArray:
Trace.Write("powers list (by array): ");
int[] powers = PowerCalculator.PowerByArray(2, 10);
foreach (int value in powers)
{
Trace.Write(string.Format("{0} ", value));
}
Trace.WriteLine("");
and next result will be shown:

power_by_array

The way is clear, but it requests to create array. Frequently we cannot allow to create a array, because number of elements and/or size of needed memory.

Usage of yield helps us to avoid creation of array:

static public IEnumerable Power(int number, int exponent)
{
int result = 1;
for (int i = 0; i < exponent; i++)
{
yield return result *= number;
}
}

Calling method Power

Trace.Write("powers list (by array): ");
int[] powers = PowerCalculator.PowerByArray(2, 10);
foreach (int value in powers)
{
Trace.Write(string.Format("{0} ", value));
}
Trace.WriteLine("");

generates next output:

power_by_yield

Reference:

yield (C# Reference)

simple example of yield (reverse)

Loops and iterators in c# (5 ways)

Statement "yield".

    When we want to use operator foreach, but want to hide details of implementation we can use interface IEnumerable.

     Review next sample:

Let's display list of cities:

Cities cities = new Cities();
foreach (string city in cities)
{
Trace.WriteLine("city: " + city);
}



where class Cities is implemented:



public class Cities
{
readonly string[] cities = { "London", "Paris", "Rome", "Jerusalem" } ;
public IEnumerator GetEnumerator()
{
return cities.GetEnumerator();
}
}



normalOrder



Seems enough simple.


Now we need display cities in reverse order



Trace.WriteLine("Reverse order: ");
foreach (string city in cities.Reverese)
{
Trace.WriteLine("city: " + city);
}



reverseOrder



To receive reverse order we can add property Reverse:



public IEnumerable<string> Reverese
{
get
{
for (int i = cities.Length - 1; i >= 0; i--)
{
yield return cities[i];
}
}
}





Reference:



yield (C# Reference)



Create Elegant Code with Anonymous Methods, Iterators and Partial Classes.

Monday, April 7, 2008

Loops and iterators in c# (5 ways).

It is suggested to inspect several ways to implement loop in c#.

For example, we need display all days: Sunday .. Saturday with help of loop (or iterators).

Operator For:

static void sample_For_Days()
{
for (int index = 0; index < DaysNames.DAYS.Length; index++)
{
string day = DaysNames.DAYS[index];
Console.Write(day + " ");
}
Console.WriteLine();
}




Operator foreach:



foreach (string day in DaysNames.DAYS)
{
Console.Write(day + " ");
}
Console.WriteLine();





Method Array.Foreach:



Array.ForEach(DaysNames.DAYS, 
delegate(string day) { Console.Write(day + " "); });
Console.WriteLine();


Operator ForEach with help of interfaces IEnumerable and IEnumerator


class implementation



public class DaysOfTheWeek_IEnumerator : IEnumerable, IEnumerator
{
int index;
public DaysOfTheWeek_IEnumerator()
{
Reset();
}
#region IEnumerable
public IEnumerator GetEnumerator()
{
return this;
}
#endregion

#region
IEnumerator
public bool MoveNext()
{
return (++index < 7);
}
public void Reset()
{
index = -1;
}
public object Current
{
get { return DaysNames.DAYS[index]; }
}
#endregion
}





usage of foreach



DaysOfTheWeek_IEnumerator week = new DaysOfTheWeek_IEnumerator();

foreach (string day in week)
{
Console.Write(day + " ");
}
Console.WriteLine();





Operator ForEach with help of interfaces IEnumerable and statement yield:



class implementation:



public class DaysOfTheWeek_yield : IEnumerable
{
#region IEnumerable
public IEnumerator GetEnumerator()
{
for (int i = 0; i < DaysNames.DAYS.Length; i++)
{
yield return DaysNames.DAYS[i];
}
}
#endregion
}





usage of foreach:



DaysOfTheWeek_IEnumerator week = new DaysOfTheWeek_IEnumerator();

foreach (string day in week)
{
Console.Write(day + " ");
}
Console.WriteLine();





Console output shows, all methods display same results:



greenshot_2008-04-07_10-41-49



Reference:



foreach, in (C# Reference)



Iterators (C# Programming Guide)



yeild (C# Reference)

Sunday, April 6, 2008

How to listen file change notification.

        When we want to receive a notifications about file system changes, we can use class FileSystemWatcher.

Code sample:

string testFolder = Path.GetTempPath();
string testFilePath = Path.Combine(testFolder, "test.tst");
File.Delete(testFilePath);

using (FileSystemWatcher watcher = new FileSystemWatcher(testFolder, "*.tst"))
{
watcher.NotifyFilter =
NotifyFilters.LastAccess | NotifyFilters.LastWrite |
NotifyFilters.FileName | NotifyFilters.DirectoryName |
NotifyFilters.CreationTime | NotifyFilters.Attributes |
NotifyFilters.Size | NotifyFilters.Security;
watcher.Created += OnFileChanged;
watcher.Changed += OnFileChanged;
watcher.Deleted += OnFileChanged;
watcher.EnableRaisingEvents = true;

File.WriteAllText(testFilePath, "text");
File.AppendAllText(testFilePath, "additional text");
File.Delete(testFilePath);
}




Output window content:



FileSystemWatcherOutputContent



Notes:



Unfortunately, my experience shows, that FilesystemWatcher doesn't work absolutely correct. In many cases, it doesn't catch a file changing.



Reference:



FileSystemWatcher Class

Thursday, April 3, 2008

How to create unique temporary file name and folder.

        As we investigated, it is possible to get temporary Windows folder by method Path.GetTempPath and create temporary file by method Path.GetTempFileName().

Unfortunately, these methods cannot help us to create unique temporary folder or temporary file (method Path.GetTempFileName() can generate only 65 536 unique file names at the same time).

It is suggested to generate unique path and name to use a globally unique identifier (GUID) with help of method Guid.NewGuid(). "Such an identifier has a very low probability of being duplicated." by MSDN.

Method, which can generate unique temporary folder:

static string GetUniquePath()
{
string uniquePath;
do
{
Guid guid = Guid.NewGuid();
string uniqueSubFolderName = guid.ToString();
uniquePath = Path.GetTempPath() + uniqueSubFolderName;
} while (Directory.Exists(uniquePath));
Directory.CreateDirectory(uniquePath);
return uniquePath;
}


The method generated and created such paths:



C:\Documents and Settings\name-f\Local Settings\Temp\b0dc9b66-a32c-586c-815b-dfed844df58c



C:\Documents and Settings\name-f\Local Settings\Temp\18a09210-9107-4a19-ab11-a246c36fec54



By the same way, can be generated and created temporary file path.



Important notes:



1. Don't forget to delete created temporary folder and files after usage.



2. Published method GetUniquePath is not protected for multi-threaded usage.



Reference:



Guid Structure



Guid.NewGuid Method

How to redirect Trace output.

As we know, for tracing we can use method Trace.WriteLine(). But usually, we want to avoid a creating of detailed log file in production mode and to enable the tracing for testing and debugging purposes only by a configuration changing. So, we should find a way to redirect output of Trace.WriteLine() from standard output to a log file and configures the redirection without rebuilding of application.

Let's write next c# code:

Trace.WriteLine("messageTrace");
Trace.WriteLine("messageError", "Error");
Trace.TraceError("traceErrorMessage");

and define .config file:

redirectTrace_va_ConfigFile

Thus, we delete "Default" Trace Listener and add our "myListener' of type TextWriterTraceListener with parameter (log file name) c:\myListener.log.

Additionally, attribute "autoflush" is set in True and method Trace.WriteLine() will store input messages to log file immediately.

Content of file myListener.log:

myListenerLogFileContent

Reference:

How to configure Trace listener

Tuesday, April 1, 2008

How to receive temporary path and file name (c#).

    To receive standard Windows temporary path we can use c# method Path.GetTempPath().

To receive uniquely temporary file we can use method Path.GetTempFileName(). The method creates a zero-byte in temporary folder and returns a full path of that file. Path of the file is created by format: <temporary folder>\tmp<4 hex symbols>.tmp (for example, <temporary folder>\tmpF1FB.tmp).

   Let's investigate how a method GetTempFileName creates a uniquely temp file:

string tempFolder = Path.GetTempPath();
string uniqueTempFileName = Path.GetTempFileName();
string tempFolder_via_Environment = Environment.GetEnvironmentVariable("TEMP");

Debug.WriteLine("tempFolder: " + tempFolder);
Debug.WriteLine("tempFolder_via_Environment: " + tempFolder_via_Environment);
Debug.WriteLine("uniqTempFileName: " + uniqueTempFileName);

for (int i = 0; i < 0xFFFF; i++)
{
uniqueTempFileName = Path.GetTempFileName();
Debug.WriteLine("uniqTempFileName: " + uniqueTempFileName);
Debug.WriteLine(String.Format("File {0} exists: {1}", uniqueTempFileName, File.Exists(uniqueTempFileName)));
}
Output Window:



output1



So, we can see rule, how GetTempFileName builds file name: "tmp" + counter + ".tmp". If a  file with next temporary file name exists, then GetTempFileName will generate next temporary file name.



File with name tmp3DBA.tmp was created manually and see result (tmp3D9, tmp3DBB) in Output Window



output2



When all temporary names will be created, that exception IOException will be raised:



exceptionQuickWatch



Reference:



Path.GetTempPath Method



Path.GetTempFileName Method