C# Tips part-II

Command line tool syntax

Command line interface (CUI) designs for many of the tools found with VS or in Windows were to include a bunch of individual commands or exe with options or flags.

To get a directory listing: dir <options> as in dir c:\temp /w
To create a directory: md c:\temp\foo
To delete a directory: rd /s c:\temp\foo

So even though all the tasks pertain to directory or path handling , you need to know three command to do the task. This design is slowly changing to the format of command <action> [</options:attributes>]

For example if we change the above commands to this format with the common command called dir, we will be getting
To get a directory listing: DIR list c:\temp /w
To create a directory: DIR make c:\temp\foo
To delete a directory: DIR rem c:\temp\foo /s

So effectively user learning is reduced. One can argue that he still needs to remember the names of the actions. But in the previous case he needs to remember rd, md, dir. Now he knows everything to do with path handling is to be done with DIR. So he can run DIR /? to get the list of actions and then do a DIR list /? to know the options for listing. The other advantage is namespace pollution in terms of the names of the executables also reduces.

This new format has also been adopted in the VS as in the source control tool. So to get the listing of all workspaces on MyServer you run the command 
h.exe workspaces /s:MyServer
To create a new workspace you run the command
h.exe workspace /new MySpace /s:abhinab-test
I guess going forward we will see more and more of the standard OS commands also taking up this format. A very common example is the NET command.

.NET API's are not always honest

First a quiz, assuming that all required priviledges is there what is the output of the following code. All the important bits are marked in bold

class Program

{

static void Main(string[] args)

{

    string dirName = @"c:\a.";

    try

    {

        System.IO.Directory.CreateDirectory(dirName);

        Console.WriteLine("Created {0}", dirName);

        Console.WriteLine( System.IO.Directory.Exists(dirName) ?

                            "Dir exist": "Dir doesn't exist");

    }

    catch (Exception ex)

    {

        Console.WriteLine("Failed to create directory {0}: {1}",
                           dirName, ex.Message);

    }

}


The output is 
Created c:\a.
Dir exist

The problem is if I go to C:\ I see a folder names a and not a. The dot at the end is conveniently dropped. What more interesting is that even though a. does not exist the Directory.Exists API returns true. Windows does not support files and folders with a dot at the end. If you use command window to create a file with a dot at the end then you simply get the file without the dot and no error is reported. .NET Directory API's exactly simulate this, but the question is do I want the simulation? I'd like to see API's being honest and report issues if it fails to do something. API's are used at a lot of places and the burden of checking should be done inside the API and not on code calling the API. 

In VSTS we just got hit by a bug due to this. When you create a Build Type using the the Wizard, the user can enter names with a DOT at the end. We then create a folder with that name and check the whole thing into Team Foundation Source Control. The problem is what gets created is a and not a. So even though you wanted to create a Build Type named a. you have one named a and all sorts of weird things happen after that. Though this is kind-of a corner situation but still I'd prefer a more honest API anyday.

The CLR Nullable DCR works!!!!!

CLR took a DCR (Design Change Request) some time back on how nullable types are implemented. I found from one of the internal DLs that the fix was already in the RTM bits.

I wrote a small piece of code which should work only with the DCR changes and kept it aside so once this DCR gets implemented I'd try it out. So each time I upgraded to a new build of VS/CLR I built/ran this code to see if it works. And it just did, with my todays upgrade to about 10 day old build in our lab. The new nullable type after becoming a basic runtime intrinsic just rocks. I have put in comment all the failures that used to happen previously with the same piece of code.


// this code works only with the latest bits of
// Visual Studio 2005 (C#2.0) and will fail to
// compile/run with older Beta2 bits

static void Main(string[] args)
{
    int? val = 1;
    int? nullval = null;

    // this always worked
    if (nullval == null)
        Console.WriteLine("It worked");

    // this used to fail before and I think one of
    // the biggest issue with the previous implementation
    object nullobj = nullval;
    if(nullobj == null)
        Console.WriteLine("It worked");

    // previously required 
    // box = Nullable.ToObject<int>(val); argh!!!!
    object box = val;

    // If you do not need exceptional code
    // (that's code that throws exception)
    // you needed to do int? unbox = Nullable.FromObject<int>(box);
    int? unbox = (int?)box;
    if (unbox == val)
        Console.WriteLine("It worked again");

    int intval = (int)box;
    if (intval == val.Value)
        Console.WriteLine("attained Nullable Nirvana");

    int x = 10;
    object y = x;
    // Previously Exception!!! cast is not valid
    int? z = (int?)y;

    IComparable c = val;
    // Previously Exception!!! : object type cannot be
    // converted to target type
    if(c.CompareTo(box) == 0)
        Console.WriteLine("I have seen it all");

    // compilation failure
    IComparable<int> ic = val;
    if(ic.CompareTo((int)box) == 0)
        Console.WriteLine("Wow there is even more to see");
}

The output of the program is

It worked
It worked
It worked again
attained Nullable Nirvana
I have seen it all
Wow there is even more to see

Its not a good idea to use Console colors too much

With Whidbey (VS2005) managed Console based applications have got a boost with new additions to the System.Console namespace. You can now change the color, size, buffer-size, cursor-size, cursor-position, window-title directly from a managed application without PInvoke.

However, just because it can be done easily, doesn't mean that it should be used. If you are developing a console based game or something similar like a chat client you have the liberty to do this. Otherwise think twice (or thrice) before you play around with any of these settings. The reason is simple most people (like me) will get super annoyed if for some reason the console window suddenly jumps and resizes when I run a program. 

If you think that doing some thing simpler like changing the text color (using Console.ForegroundColor) to draw attention is Ok, consider it carefully. It might just not work, could look horrible on some specific console setting or might convey the wrong meaning. I have listed below some common usage of changing these setting programmatically and why they might not work. Most programmers agree and understand that playing with console window size or buffer-size is not a good idea and do not use it so I have omitted them from here.

Changing text color using Console.ForegroundColor

Warning and Error Messages: Using different colors for output text, like yellow for warnings and red for error might be fine. You just need to ensure that you use the right set of colors as their meaning are deeply bound in the mind of the users. The following table typically works

· Yellow: warning
· Red: Error
· Green: Pass, success messages
· Cyan: Information

Do NOT use colors when its not absolutely required: Its best to avoid using colors when not absolutely required. In most cases it'll lead to trouble and rarely be of any benefit. See the following example where the prompt comes in yellow. Since this is a console based application it would have blocked until I entered the required inputs so drawing attention with yellow does not add any value. Since yellow is associated with warning, a first-time user might thing that something is wrong and he's required to rectify this by entering some server name.

Welcome to my tool
Server : MyServer
Username: Abhinaba

Do NOT use a dark color for text: People do change the background color of the console. I use Teal and DarkBlue often, so ensure that you do not choose one of the darker colors for the text as it might coincide with the background color of the console window and your text will be invisible. I once came accross a tool which used blue for text entered by the user. I had launched that application on a blue-background console. Since I was using the application for the first time, I had a hard time figuring out what was going on, as I couldn't see what I was typing

The safe colors are Gray, Green, Cyan, Red, Magenta, Yellow and White. However sometimes even these colors in combination with background colors cause eye-sore as in

Some error message!!

Do restore the original color: Even if you use any of the above colors remember to switch the color back to the original color. Use some thing like

public void ShowError(string message)
{
    ConsoleColor orgCol = Console.ForegroundColor; 
    Console.ForegroundColor= ConsoleColor.Red;
    Console.WriteLine(message);
    Console.ForegroundColor = orgCol; // restore color
}

This might look trivial, but can be a big source of annoyance. Like your application gets an exception, the exception-handler sets color to red, shows the error message and the application exits. Now whatever I type in that console window is in Red!!! 

Using Console.BackgroundColor

Do NOT change the background color:
Console.BackgroundColor = ... is bad. The reason being that the color is changed only for subsequent text and it looks horrible as below

Text before color change
Text after I changed the background col to cyan

Even though very few people intentionally do this, it does creep into application. Sometime back in some error message code I saw this.
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error!!!");

This went undetected in test, until someone opened it in a Teal window and this is what came up

Some error message!!

laying with cursor

CursorVisible: You might want to hide the cursor when showing some output using Console.CursorVisible = false. Just remember to revert it back to the same visibility state as it originally was.

CursorPosition: Jumping the cursor around in the screen is not a main-stream scenario and most console application don't use it. However, I have seen some tools like build-systems use this to show subsquent outputs in the same line. Consider the following code

int currPos = Console.CursorTop; // get the current pos 
for (int i = 0; i < 30; i++) 
{
    Console.WriteLine("Counting {0}", i); 
    Console.CursorTop = currPos; // Go back to the same line
    System.Threading.Thread.Sleep(200);
}

This shows the counter in the same line. This might be required in your application. However, in some cases its over-done and you can simply live without it...

Most programmers are used to UI guidelines. Unfortunately most of these guidelines ingnore command line interface and are silent on them.


You can reach author from the following email-id.

abhinaba@gmail.com

 




Added on September 14, 2007 Comment

Comments

Post a comment