Stacking Using

A few days ago, Benjamin pointed me to a feature in C#, I was not aware of, yet. You can stack using statements. In the following I will show an example where this might come in very handy.

I recently worked on a project where we had to process large text files (with large I mean 14GB each). In a pre-processing step we cleaned up the files, processed each line, validated it against a set of rules and then either wrote it back to a output file or a temporary which required further processing steps. Due to the complexity of the validation we decided to go with a small C# program that does the job.

A fast and convenient way was utilizing a set of StreamReaders and StreamWriters and applying using statements a to read and write the files. As Anoop pointed out, not using usings is one of a common mistakes .NET developers should avoid. Eventually, the code looked similar to the following example by cascading the using statements.

using (StreamReader reader = new StreamReader(@"c:input.txt"))
{
    using (StreamWriter successWriter = new StreamWriter(@"c:success.txt"))
    {
        using (StreamWriter failWriter = new StreamWriter(@"c:fail.txt"))
        {
            // all the magic happens here
        }
    }
}

That would be the way many developers would write the code, and if you have a look at the MSDN documentation about using statements  this seems to be the way to do it. But the C# 4.0 Language Specification does give you an hint that there is more you could do.

For a using statement stmt of the form:

using ( resource-acquisition ) embedded-statement

The definite assignment state of v at the beginning of resource-acquisition is the same as the state of v at the beginning of stmt.

The definite assignment state of v on the control flow transfer to embedded-statement is the same as the state of v at the end of resource-acquisition.

What’s not obvious here, is the fact that you can stack using statements utilizing one code block. In this case you embedded-statement is another using statement. In fact that’s not different how most of us use cascading for and foreach loops. In fact, this is not a new feature of C# but something you might not have considered before.

using (StreamReader reader = new StreamReader(@"c:input.txt"))
using (StreamWriter successWriter = new StreamWriter(@"c:success.txt"))
using (StreamWriter failWriter = new StreamWriter(@"c:fail.txt"))
{
    // all the magic happens here
}

Writing the code like this reduces a lot of noise and indentation in your code, keeps the resource acquisition tight and might be definitely worth keeping in mind.

P/Invoke Data Type Matching

Creating this table took a while, but saved me hours…

Windows Data Type .NET Data Type
BOOL, BOOLEAN Boolean or Int32
BSTR String
BYTE Byte
CHAR Char
DOUBLE Double
DWORD Int32 or UInt32
FLOAT Single
HANDLE IntPtr, UintPtr or HandleRef
HRESULT Int32 or UInt32
INT Int32
LANGID Int16 or UInt16
LCID Int32 or UInt32
LONG Int32
LPARAM IntPtr, UintPtr or Object
LPCSTR String
LPCTSTR String
LPCWSTR String
LPSTR String or StringBuilder*
LPTSTR String or StringBuilder
LPWSTR String or StringBuilder
LPVOID IntPtr, UintPtr or Object
LRESULT IntPtr
SAFEARRAY .NET array type
SHORT Int16
TCHAR Char
UCHAR SByte
UINT Int32 or UInt32
ULONG Int32 or UInt32
VARIANT Object
VARIANT_BOOL Boolean
WCHAR Char
WORD Int16 or UInt16
WPARAM IntPtr, UintPtr or Object

WaitOne and PInvoke

Unfortunately, there is no way to copy a .NET desktop application to a compact framework based system. The compact framework does only support a subset of the .NET library.

Two typical problems while migrating a multi-threaded application to the Compact Framework can be solved as following:

The first issue appears when using the Sleep-method of threads.

System.TimeSpan yield = new System.TimeSpan(10);
System.Threading.Thread.Sleep(yield);

The compact framework does not support any signature accepting TimeSpan as parameter. Simply convert the value to an integer using the milliseconds solves this one.

System.TimeSpan ts = new System.TimeSpan(10);
int yield = ts.Milliseconds;
System.Threading.Thread.Sleep(yield);

More complex is the usage of the WaitOne-method. WaitOne only provides a signature without any parameters on the compact Ffamework. A simple solution is the usage of the following PInvoke

[System.Runtime.InteropServices.DllImport("CoreDll.dll")]
private extern static Int32 WaitForSingleObject(System.IntPtr Handle,System.Int32 Wait);

Using this you can substitute calls similar to this

foo.WaitOne((int)((bar - System.DateTime.Now.Ticks), false);

by the flowing lines to achieve the same result:

System.IntPtr hProcess = foo.Handle;
System.Int32 wait = (int)((bar - System.DateTime.Now.Ticks));
WaitForSingleObject(hProcess, wait);