Wednesday, August 30, 2006

Arrays of methods in C#

How many times have you written code that goes something like this:

if (someValue == SomeEnum.Type1)
Method1("value 1");
else if (someValue == SomeEnum.Type2)
Method2("value 2");
else if (someValue == SomeEnum.Type2)
Method3("value 3");

maybe you used a switch statement to accomplish the same kind of thing.


You can see the pattern there, Method1, Method2 and Method3 all have the same signature and they get executed when the value Type1, Type2 or Type3 is passed. Wouldn't be nice if we could reduce that to a single line?


That's exactly what arrays of methods can do for you, let's see an example, before we can use them we need to set them up


Since all the methods share the same signature it means we can use a delegate to represent all of the methods.

delegate void AddStringDelegate(string someValue);

Now we can declare an array of delegates:

AddStringDelegate[] addStringMethods;

We will use an enumeration to access the items of the array:

enum StringType {
Type1,
Type2,
Type3,
Type4
}

Then we need the actual methods declaration:

void AddStringType1(string someValue) {
OutputText(string.Format("String Type 1: {0}", someValue));
}
void AddStringType2(string someValue) {
OutputText(string.Format("String Type 2: {0}", someValue));
}
void AddStringType3(string someValue) {
OutputText(string.Format("String Type 3: {0}", someValue));
}

finally, on the constructor of our class, we assign the methods to the array to get our array of methods:

addStringMethods = new AddStringDelegate[3];
addStringMethods[(int)StringType.Type1] = new AddStringDelegate(AddStringType1);
addStringMethods[(int)StringType.Type2] = new AddStringDelegate(AddStringType2);
addStringMethods[(int)StringType.Type3] = new AddStringDelegate(AddStringType3);

It's ready to be used, let's see what the implementation looks like:

public void AddString(string someValue, StringType stringType) {
addStringMethods[(int)stringType](someValue);
}

As you can see we can access the required method by converting the enumeration to an int type, our code was just reduced to 1 line; passing the desired enum type gets to our method in one shot


I'll let you decide when you want to use this technique, I wouldn't recommend using it in a small class that gets instantiated and thrown very fast and often, but in some cases it might even be useful there


I think it would be specially useful if we had this kind of pattern inside a singleton class where the class could potentially live a lot longer, you could do all the work to initialize your array of methods and be able to re-use it effectively


Here's the full code for this example, on my next post I'll show you how you could use this technique to implement some kind of factory pattern or what is sometimes referred to as simple factory pattern

class FileGeneratorBase {
delegate void AddStringDelegate(string someValue);

AddStringDelegate[] addStringMethods;

public FileGeneratorBase() {
addStringMethods = new AddStringDelegate[4];
addStringMethods[(int)StringType.Type1] = new AddStringDelegate(AddStringType1);
addStringMethods[(int)StringType.Type2] = new AddStringDelegate(AddStringType2);
addStringMethods[(int)StringType.Type3] = new AddStringDelegate(AddStringType3);
addStringMethods[(int)StringType.Type4] = new AddStringDelegate(AddStringType4);
}

public void AddString(string someValue, StringType stringType) {
addStringMethods[(int)stringType](someValue);
}
void AddStringType1(string someValue) {
OutputText(string.Format("String Type 1: {0}", someValue));
}
void AddStringType2(string someValue) {
OutputText(string.Format("String Type 2: {0}", someValue));
}
void AddStringType3(string someValue) {
OutputText(string.Format("String Type 3: {0}", someValue));
}
void AddStringType4(string someValue) {
OutputText(string.Format("String Type 4: {0}", someValue));
}
void OutputText(string someValue) {
Console.WriteLine(someValue);
}
}

class Program {
static void Main(string[] args) {
FileGeneratorBase fg = new FileGeneratorBase();
fg.AddString("some value", StringType.Type1);
fg.AddString("some other value", StringType.Type2);
fg.AddString("one last value", StringType.Type3);
fg.AddString("testing out of bounds", StringType.Type4);
Console.ReadLine();
}
}

updated: To initialize the array using the same enum instead of hardcoded values of 0..4

Monday, August 28, 2006

Hiding generics complexity part II

on previous articles I talked about complex generic types

Multidimensional generics

and how to make those types more readable by using aliases

Hiding generics complexity

    using System.Collections.Generic;
using FilesList = List<string>;
using FoldersWithFiles = Dictionary<string, List<string>>;
using ComputersWithFiles = Dictionary<string, Dictionary<string, List<string>>>;

Here is another technique to accomplish readable code while still using generics.


We can subclass the generics in this way:

    class FilesList2 : List<string> { }
class FoldersWithFiles2 : Dictionary<string, List<string>> { };
class ComputerFiles2 : Dictionary<string, Dictionary<string, List<string>>> { }
class ComputersWithFiles2 : Dictionary<string, Dictionary<string, List<string>>> { }

The code to use them is pretty much the same as when we were using aliased generics, but there is a little "problem", KeyValuePair is a struct and as such it doesn't support inheritance, which means we can't apply this technique to this type, so we can combine aliased types for the KeyValuePair and sub-classing for the rest


This brings us to another point, when we have code like this:

Console.WriteLine("List of Directories with files");
FoldersWithFiles2 foldersWithFiles = GetFoldersWithFiles();
foreach (FoldersWithFilesPair kv in foldersWithFiles) {
Console.WriteLine(string.Format(" Folder: [{0}]", kv.Key));
ListFiles((FilesList2)kv.Value);
}

If we want to use FoldersWithFilesPair.Value as a FilesList2 type we have to typecast it, this is because FilesList2 is a new type and FoldersWithFilesPair.Value is a List<string>; remember that C# is a type-safe language.


Subclassing the generic types in this way can give you more benefits than simply more readable code, as any other class they can implement methods so you can assign them more specific tasks/methods that reflect more accurately their responsibility


There is a big difference betwee using aliased generics and subclassed generics, aliased types are the exact same type, just with a different name, subclassed generics are a new name and a new type.


This is it for now, you now have a new tool in your toolbox, as with everything else in life, don't abuse it!


Hope to see some code where people are using these techniques


as promissed, here is the full source code, the code is free as in LPGL

Sunday, August 27, 2006

the church of... Google?

We at The Church Of Google believe a convincing argument can be made stating that the search engine Google is the closest mankind has ever come to experiencing an actual Deity. It is the ultimate bridge between people and information.

 

Thou shalt have no other Search Engine before me, neither Yahoo nor Lycos, AltaVista nor Metacrawler. Thou shalt worship only me, and come to Google only for answers.

..way too much free time on their hands

what!? you are going to join?

Friday, August 25, 2006

The programmer's Bill of Rights

I'm all up for this:

I propose we adopt a Programmer's Bill of Rights, protecting the rights of programmers by preventing companies from denying them the fundamentals they need to be successful.

...is just weird that the link is 666...

finally {} is not a good place to commit your transactions

I just fixed some code (not written by me!) that went something like this:

transaction = connection.BeginTransaction();
try {
try
{
//***.... database operations here...
} finally {
transaction.Commit();
}
} catch {
transaction.RollBack();
}

First of all, there is a bug there, if an exception is ever raised, it will raise a new exception because it cannot rollback a transaction that was committed (the message will not be that clear, but that's what it means, the exception says something about unable to complete the operation due to the current state of the object), and you'll lose the original exception that you got


Second, it's just wrong, it defeats the purpose of using a transaction, is like you are saying


//*** delete some records


//*** update some records


//*** some db operation that caused some exception


//*** finally, commit what I had done so far


leaving your data in an unknown state because you commited all the operations up until it failed


hint: always use "using" for any DB related stuff (connections, commands, transactions, etc)

Tuesday, August 22, 2006

Hiding generics complexity

On my last post I showed you some wicked use of generics, Ayende says he can't read code like that and provided an alternative; I agree with him, it is very ugly code, but there is hope!

here's the equivalente code for the first section (note that I'm still using generics, even if it doesn't look like it), where we wanted to store a list of file names:

FilesList filesList = GetFilesList();
ListFiles(filesList);
Then we have the bidimensional generic, to store folder name and the files in it:
FoldersWithFiles foldersWithFiles = GetFoldersWithFiles();
foreach (FoldersWithFilesPair kv in foldersWithFiles) {
Console.WriteLine(string.Format(" Folder: [{0}]", kv.Key));
ListFiles((FilesList)kv.Value);
}

And finally where we store computer names, with the folders, with the files in it:

ComputerFiles computerFiles = GetComputerFiles();
foreach (ComputersWithFoldersPair kv in computerFiles) {
Console.WriteLine(string.Format("Computer: [{0}]", kv.Key));
foreach (FoldersWithFilesPair kv1 in kv.Value) {
Console.WriteLine(string.Format(" Folder: [{0}]", kv1.Key));
ListFiles((FilesList)kv1.Value);
}
}
And my last example would now look like this:
ComputerFiles computerFiles = new ComputerFiles();
instead of this:
Dictionary<string, Dictionary<string, List<string>>> ComputerFiles = 
new Dictionary<string, Dictionary<string, List<string>>>();

Now, if the code is equivalente and I'm still using generics, what did I do?


I am using aliased generics (yup, invented here too J) which give me friendly names, instead of the ugly multidimensional generics syntax

Here's the aliases declaration:
using System.Collections.Generic;
using FoldersWithFilesPair = KeyValuePair<string, List<string>>;
using ComputersWithFoldersPair = KeyValuePair<string, Dictionary<string, List<string>>>;

using FilesList = List<string>;
using FoldersWithFiles = Dictionary<string, List<string>>;
using ComputerFiles = Dictionary<string, Dictionary<string, List<string>>>;

The best of both worlds, you can use complex generic data structures and keep your code readable.


You put all the uglyness in a simple place, and you are able to use friendly names which look like normal classes, plus you get more extensibility because you could change the signature of the aliased generics without breaking the code.


On my next post I'll show you another technique to accomplish the same thing, and some gotchas, then I'll put the full source code in a zip file so you can download it.

Blogging since 1969

 some people have just been blogging for too long

(oh yeah, and I wanted to test the Live Writer image uploading capabilities...)

Monday, August 21, 2006

C# multidimensional generics

You can think of Generics as Arrays on steroids or Collections on steroids or a combination of both, they offer an extensible list of items with type safety; or as MSDN puts it:

Generics allow you to define type-safe data structures, without committing to actual data types.

One thing that I haven't seen much is how you can use multidimensional generics (yup, invented here J), let me explain what I mean

let's say we wanted to store a list of file names, we could do something like:




List<string> filesList = GetFilesList();
ListFiles(filesList);


now, we want a list of directories with the files in them, we could use a bidimensional generic type to keep the directory name on a dictionary key and the list of files on the dictionary value:


Dictionary<string, List<string>> foldersWithFiles = GetFoldersWithFiles();
foreach (KeyValuePair<string, List<string>> kv in foldersWithFiles) {
Console.WriteLine(string.Format(" Folder: [{0}]", kv.Key));
ListFiles(kv.Value);
}


finally, let's say we want a list of computers, with folders that contain files, we can use a multidimensional generic type that has the computer name on a dictionary key, and the folders with files on another dictionary stored as the key:




Dictionary<string, Dictionary<string, List<string>>> ComputerFiles = GetComputerFiles();
foreach (KeyValuePair<string, Dictionary<string, List<string>>> kv in ComputerFiles) {
Console.WriteLine(string.Format("Computer: [{0}]", kv.Key));
foreach (KeyValuePair<string, List<string>> kv1 in kv.Value) {
Console.WriteLine(string.Format(" Folder: [{0}]", kv1.Key));
ListFiles(kv1.Value);
}
}


For the sake of completeness here's the ListFiles function, just so you can see some cool use of generics combined with anonymous delegates:


static void ListFiles(List<string> filesList) {
filesList.ForEach(new Action<string>(delegate(string s) { Console.WriteLine(string.Format(" {0}", s)); }));
}


As you can see, with generics we can create some complex type-safe data structures, however, as always, some people will complain that multidimensional generics become very cryptic;

and you can see it if you did something like:



Dictionary<string, Dictionary<string, List<string>>> ComputerFiles = new Dictionary<string, Dictionary<string, List<string>>>();

in my next post I'll show you a couple techniques you can use to hide the generics complexity while keeping all of their benefits

Tuesday, August 15, 2006

RegisterChannel is obsolete, use RegisterChannel instead

I got this error:

Warning 6 'System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(System.Runtime.Remoting.Channels.IChannel)' is obsolete: 'Use System.Runtime.Remoting.ChannelServices.RegisterChannel(IChannel chnl, bool ensureSecurity) instead.'

It threw me off for a little while because System.Runtime.Remoting.ChannelServices.RegisterChannel doesnt' really exist

the problem there was that they just missed the .Channels part of the namespace, so it should've been:

"use 'System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(IChannel chnl, bool ensureSecurity) instead"

ok, that was the first part, now if this overload is obsolete, which one is the equivalent?

RegisterChannel(chnl, true)

or

RegisterChannel(chnl, false)

Reflector to the rescue, the equivalent is to use false as the second parameter, that's what the current function does right now when you call

RegisterChannel(chnl);

it calls:

ChannelServices.RegisterChannelInternal(chnl, false);

Monday, August 14, 2006

First bug in live write

This happens when you add multiple blogs accounts, on the last dialog if you uncheck the "switch to this blog now" (or something like that) the new blog won't appear in your list of blogs, so you are not able to switch to that

restarting the app refreshes the list

Hello world from live writer

This thing is pretty cool, it allows me to write to my multiple blogs just fine, check out their blog too

cool use of the coallesce ?? operator in C#

We just coded something like (please disregard the variable names, I'm just illustrating the point)

return myCollections.Services ?? (myCollections.Services = dbLayer.GetServices());

one-liner to do a bunch of stuff, and it's still clear what you are trying to do, if you know the ?? operator you can stop right here, if you don't let me explain a bit more

the ?? operator returns the left-hand operator if it is NOT NULL, else it returns the right operand

so this code is the equivalent of:

if (myCollections.Services == null)

  myCollections.Services = dbLayer.GetServices();

return myCollections.Services;

Wednesday, August 09, 2006

Notepad hidden features: How to use Notepad to create a (manual) log file

In case you missed it, here's how "Bush hid the facts"
To create a log file in Notepad:
1. Click Start, point to Programs, point to Accessories, and then click Notepad.
2. Type .LOG on the first line, and then press ENTER to move to the next line.
3. On the File menu, click Save As, type a descriptive name for your file in the File name box, and then click OK.
When you next open the file, note that the date and time have been appended to the end of the log, immediately preceding the place where new text can be added.
You can use this functionality to automatically add the current date and time to each log entry.

How to Use Notepad to Create a Log File

Pretty cool, everytime you open the file after that (in Notepad), it adds a timestamp
 and you can enter some text

get Delphi for free

seems like things are starting to get shape for Borland's Developer Tools Group, they are coming up with these "express" (free) and cheaper versions of Delphi, C# and C++
Turbo Delphi, Turbo Delphi for .NET, Turbo C++ and Turbo C# will be generally available in the third quarter of 2006. The Turbo Explorer editions of these products will be free. Pricing for the Turbo Professional editions will be under $500. Student academic pricing for the Turbo Professional editions will be under $100. For more information, visit www.turboexplorer.com.

August 8, 2006 - Turbos Press Release

We'll see what they can do against the Microsoft Express versions which have been out and free for a while, right now I don't see how they could compete but we'll see; if they run (and probably will) against the .NET Framework 1.1 that will discourage a lot of people

Monday, August 07, 2006

I'm natural hacker material J

Points For Style
Again, to be a hacker, you have to enter the hacker mindset. There are some things you can do when you're not at a computer that seem to help. They're not substitutes for hacking (nothing is) but many hackers do them, and feel that they connect in some basic way with the essence of hacking.
* Learn to write your native language well. Though it's a common stereotype that programmers can't write, a surprising number of hackers (including all the most accomplished ones I know of) are very able writers.
* Read science fiction. Go to science fiction conventions (a good way to meet hackers and proto-hackers).
* Train in a martial-arts form. The kind of mental discipline required for martial arts seems to be similar in important ways to what hackers do. The most popular forms among hackers are definitely Asian empty-hand arts such as Tae Kwon Do, various forms of Karate, Kung Fu, Aikido, or Ju Jitsu. Western fencing and Asian sword arts also have visible followings. In places where it's legal, pistol shooting has been rising in popularity since the late 1990s. The most hackerly martial arts are those which emphasize mental discipline, relaxed awareness, and control, rather than raw strength, athleticism, or physical toughness.
* Study an actual meditation discipline. The perennial favorite among hackers is Zen (importantly, it is possible to benefit from Zen without acquiring a religion or discarding one you already have). Other styles may work as well, but be careful to choose one that doesn't require you to believe crazy things.
* Develop an analytical ear for music. Learn to appreciate peculiar kinds of music. Learn to play some musical instrument well, or how to sing.
* Develop your appreciation of puns and wordplay.

How To Become A Hacker

Saturday, August 05, 2006

The problem of naming your blog after a technology

Specially at Microsoft, technology names change and some times they change often, I've seen quite a few blogs named after MS technologies that later change the name, some recent examples include Windows Vista and PowerShell

You can't know it all, so what to do?

You can't know it all. No matter how smart you are, no matter how comprehensive your education, no matter how wide ranging your experience, there is simply no way to acquire all the wisdom you need to make your business thrive.Donald Trump - Learning - Business - Knowledge

Learning Quotes


In the programming world we hear this more and more often, frameworks have thousands of classes, functions and features, even the people behind those frameworks don't know other parts of the framework, what makes you think you can know it all

It's key to be comfortable with your own ignorance. Understand that you can't know it all and stop trying to or pretending that you do. Understand that other people are ignorant too, and help educate them when you can rather than resenting their shortfall. On the same track, don't resent someone who's trying to teach you something either, swallow your pride and better yourself for it.

The Critical Path / eMail Newsletter / Issue 6.1



My approach to this issue is to learn the language features as good as I can, then on the features of the frameworks I make a distinction on technologies that I'm interested in learning right now and learn them, and as many others that might be useful at some point, but the point is to be aware that such features exist and what they do; that way when you actually need them you can find them a lot faster because you know there is something to do just that and you avoid reinventing the wheel in many cases

services like del.icio.us can help you with this problem, if you see something cool that you might be interested in the future you can save a link and tag it with something like "future" and you can build a list of things to learn or that you can posibly use some time later

You can't put everything in your brain, so use the existing tools to do some of that work for you

Is just like in soccer, is always good to win, but if you can't win is good to tie, if you can't tie is good to lose for as little difference as possible

Improve your tabbed browser experience

These extensions greatly improve the tabs behavior in Firefox/Flock

Ctrl Tab Preview
This is an extension that replaces the behavior of Ctrl+Tab. Instead of directly changing tab it works some thing like Alt+Tab on windows. It views preview of the tab and you can change directly to the tab you want to or just go through all tabs to see what you got in them. A pictures tells more then thousands words so look at the pictures or try it.


SessionSaver
SessionSaver restores your browser -exactly- as you left it, every startup, every time. Not even a crash will phase it. Windows, tabs, even things you were typing -- they're all saved. Use the menu to add + remove sessions; right, shift, or middle-clicking will delete. "Simple mode" for peace of mind, or "Expert mode" for advanced flexibility. Just Click. Install. Rad.

Perma Tabs
Adds the ability to turn tabs of your choice into permanent tabs ("permaTabs") that can't be closed, and stick around between sessions.

Multiple home pages in your browser

One of those things that not many people know, most modern browsers these days allow multiple home pages.

Firefox/Flock



Internet Explorer



Opera also allows you to do it, quite a bit more complicated, but can be done

Multiple home pages in Opera

In Firefox/Flock there is also an extension that allows you to cycle your home pages:

Home Page Cycler
Load a different home page each time Firefox starts.

Tuesday, August 01, 2006

Don't click it, really

quite a different user interface, what do you think?

Don't click it