Jeroen Haegebaert

To content | To menu | To search

Monday 31 January 2011

String compression using GZipStream

I 've been looking up this sample code for working with GZipStream (compressing string to byte array and vice versa) several times now. There are numerous samples available that show how to work with GZipStream, but most of them seem overly complex for the task at hand. I've settled on this version:

   public static byte Compress(string text)
       using (var ms = new MemoryStream())
           using (var zip = new GZipStream(ms, 
           using (var writer = new StreamWriter(zip, Encoding.UTF8))
           return ms.ToArray();
   public static string Decompress(byte[] compressed)
       using (var ms = new MemoryStream(compressed))
       using (var zip = new GZipStream(ms, CompressionMode.Decompress))
       using (var sr = new StreamReader(zip, Encoding.UTF8))
           return sr.ReadToEnd();

Saturday 24 July 2010

Chained method syntax in IronPython (alternative to extension methods)

Extension methods, Lambda expressions and IronPython

Together with extension methods, lambda expressions are the enablers of linq. IronPython (and python) support the notion of lambda expressions. However, there is no direct support for calling Extension methods in IronPython (yet). That is to say, you can call them, but only in their 'static method in static class form', like so:

customers = GetCustomers()
namesOfJohns = Enumerable.Select(\
                    customers, \
                    lambda c : c.Name.StartsWith("John")), \
                lambda c : c.Name);

This works, obviously, but the syntax is hardly readable, you will agree. Not convinced? What about this:

namesOrJohnsOrdered = Enumerable.Select(\
                customers, \
                lambda c : c.Name.StartsWith("John")), \
             lambda c : c.BirthDate), \
          lambda c : c.Name), \
       lambda c : c.Name);

In C#, using the Chained Method syntax, it looks like this:

var namesOfJohnsOrdered = customers
                .Where(c => c.Name.StartsWith("John")
                .OrderBy(c => c.BirthDate)
                .ThenBy(c => c.Name)
                .Select(c => c.Name);

I rest my case :-).

So, what do we want to achieve?

Well, as we saw, Python does have the notion of lambda expressions, so we’d like to reuse those. But can we achieve the chained syntax in IronPython, similar to the C# example above? If we could, it would look like this:

   namesOfJohnsOrdered = customers.\
      .Where(lambda c : c.Name.StartsWith(“John”))\
      .Select(lambda c : c.Name)

How to achieve this?

If you think about it, extension methods are in fact a fancy way to implement the decorator pattern.

The decorator pattern can be used to make it possible to extend (decorate) the functionality of a certain object at runtime, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new decorator class that wraps the original class.

What if we wrote a class that extends IEnumerable<T>, with wrapper functions for the all linq operators we want to use? Here's what I have in mind:

public class ToLinq<T> : IEnumerable<T>
    private readonly IEnumerable<T> _wrapped;

    public ToLinq(IEnumerable<T> wrapped)
        _wrapped = wrapped;

    public ToLinq<T> Where(Func<T, bool> predicate)
        return new ToLinq<T>(_wrapped.Where(predicate));

    public ToLinq<U> Select<U>(Func<T, U> selector)
        return  new ToLinq<U>(_wrapped.Select(selector));

    public bool Any(Func<T, bool> predicate)
        return _wrapped.Any(predicate);

    public int Count()
        return _wrapped.Count();

    // etc, you get the idea


We can use this from IronPython as follows:

import clr

from IronPythonLinqBridge import *
from ConsoleApplication3 import Customer

def Enumerate(customers) :
    johns = ToLinq[Customer](customers)\
        .Where(lambda c: c.Name.StartsWith("John"))\
        .Select(lambda c: c.Name)
    for name in johns : print name

As you can see, the ToLinq class in IronPython is called like a method. This covers the scenario where we have some .Net code that passes an IEnumerable sequence to IronPython. It also works with standard python sequences.

This script is called from C# code like so:

var engine = Python.CreateEngine();

dynamic enumerator = engine.CreateScope();
engine.Execute(File.ReadAllText(""), enumerator);

var customers = new[]
                        new Customer {Name = "John Johnson"},
                        new Customer {Name = "Gosse Jordan"},
                        new Customer {Name = "John Donahue"},
                        new Customer {Name = "Andie Reynard"}

Tuesday 2 March 2010

Patch for Visual Studio 2010 RC intellisense crash

If you are confronted with the dreaded intellisense-related crash in Visual Studio 2010 RC, there's a patch available on microsoft connect that should fix the root cause.

Monday 31 August 2009

compiling notepad2 under Visual Studio 2010

Notepad2 is an excellent lightweight text editor, intended as a replacement for Notepad. I like to call it 'notepad on steroids': a simple text editor, but still containing most features you've come to expect using more advanced (and often bloated) editors. The tool written by Florian Balmer and the best part is that it's open source!

Now Florian is using Visual Studio 6.0 for developing his app, which certainly does the job, but I didn't really feel like installing 6.0 alongside Visual Studio 2010 Beta 1. Turns out it's relatively easy to get it compiled under 2010 (will probably also work in Visual Studio 2008 and 2005, but I didn't try myself).

Now Flo pointed me to some posts explaining what to do here and here, but these are in Korean, so I thought I'd share my findings here.

First of all, download the Notepad2 source code. I started with v4.0.22.

You also need to download the corresponding version of the scintilla source code. Put this in in a subfolder called 'scintilla' in the same folder as the Notepad2 solution file (notepad2.sln). Notepad2 4.0.22 is based on scintilla 1.79.

Now open the Notepad2.sln solution in Visual Studio 2010. Next-Next-Finish to upgrade the .sln and .vcproj files. The upgrade wizzard will create a file called notepad2.vcxproj, and notepad2.vcxproj.filters, making the .vcproj file obsolete.

Finally, you will notice that the solution does not build yet. You need to the following edits. Start with applying the instructions from Flo's readme: disable the definition of LINK_LEXER in scintilla\keywords.cxx:

    #define LINK_LEXER(lexer) extern LexerModule lexer; ...

must be replaced with:

     #define LINK_LEXER(lexer) void(0)

Now I got a compiler error complaining that LPSHELLICON is not defined. In the file dlapi.h, I added the following:

    #ifndef LPSHELLICON
    typedef struct IShellIcon IShellIcon, *LPSHELLICON;

Finally, I remained with a link error, something about the manifest. This can be resolved by commenting out the line starting with 'IDR_RT_MANIFEST' in the file Notepad2.rc.

EDIT - Disclaimer: Florian notified me that this may have unwanted side effects. Do this at your own risk. Your PC may blow into pieces. You have been warned (but it Works On My Machine :-)). I may look into the details of it in a future post.

Anyway, that's it! Everything should compile and run now.

Friday 26 June 2009

Delivering mail to a local folder for testing purposes

Adding the following configuration snippet to the web.config file will ensure that System.Net.Mail.SmtpClient is configured to save mails to a local folder. When moving to production, just replace this with the configuration using an smtp server, and you should be good to go!

      <smtp deliveryMethod="SpecifiedPickupDirectory">

Saturday 31 January 2009

comments and regions

Let me put something straight right up front: I'm mostly against comments, XML documentation and regions in C# code. They might have their uses here and there, but most uses of comments/XML documentation/regions that I encounter just get in the way of what I really want to understand: the code. Most of the time, these things are no more than some bandage over a stinky mess of awfully written code.

I couldn't agree more with these guys:

These three aspects (XML documentation, plain comments and regions) are in most cases just an excuse for the guys coming after you: 'Hey, here's the code I'm giving you to maintain. It's full of crap and I don't want to take the effort to give you something well structured, but at least I added some comments to it, so you should be ok, right?'

I'm not saying that a good comment here and there can not be of use. Indeed, in some cases it's justified to explain WHY a certain approach was taken. But for the most part, your intent should be clear through the code structure, and wisely choices of class- and method names.

ok, rant over.

Sunday 18 January 2009

Mocking HttpContext: why would you do that?

You can just override the HttpContext.Current property with your own instance:

            HttpContext.Current = new HttpContext(
                new HttpRequest(filename, url, querystring),
                new HttpResponse(new StringWriter())

This allows you to easily unit test code that depends on HttpContext.Current. I didn't realize this could be done until I read Ayende's post on the subject...

Friday 19 September 2008

free/open source .Net PDF library

An open source .Net PDF libary:

Tuesday 26 August 2008

Resolving merge conflicts with git and kdiff3

A little bit confusing to get started, but in the end quite simple. To get started, the easiest is to put the kdiff3 folder in your path.

Assume you're on branch 'master' and want to merge changes from 'master' to 'working'

C:\Projects\GitTest>git checkout working
C:\Projects\GitTest>git merge master
Auto-merged blabla.txt
CONFLICT (content): Merge conflict in blabla.txt
Automatic merge failed; fix conflicts and then commit the result.

To fix the conflicts using kdiff3, first you need to tweak the kdiff3 configuration a bit: start kdiff3, and go to Settings, Configure KDiff3, Integration. Under 'Command line options to ignore', add ';--'. To resolve conflicts, you can now use:

git mergetool -t kdiff3

To permanently configure kdiff3 as the merge tool (so you don't need to specify the '-t kdiff3' anymore):

git config merge.tool kdiff3

Saturday 23 August 2008

Dealing with the quirks of TFS using git, take 2

UPDATE: there is git-tfs now, no need to bother with this post

I'm on a mission to ease the pain dealing with some of the quirks of TFS. I've kind of reversed my previous strategy, which boiled down to synchronizing my TFS working copy to an offline working copy managed by git. It didn't feel right, and turned out to be quite unworkable. I'm trying another way now, which is to manage my TFS working copy also with git.

Initializing git:

git init
git add *.csproj *.cs [+ other file types]
git commit -m "initial commit"

This created the master branch with a bunch of files in it. I also added a .gitignore file with all patterns, files and folders I don't want to manage in git (*.suo, *.resharper, *.user, bin, obj etc). Then I created a working branch in which I will be able to do intermediate checkins of unfinished work.

git branch working
git checkout working

Now when changing stuff inside this working copy, I still have to make sure everything is properly checked out from TFS, that doesn't change. But I don't really care anymore since I now use git for checking the status of my work (git diff and git status are your friends). There are 2 operations that need attention: updating my working copy with the changes from other team members, and committing my own changes to the TFS repository.


To update my working copy from TFS, first I make sure everything is committed in my git working branch (git commit -a -m "some meaningful comment"). Then I take the following steps:

git checkout master
tf get . /recursive
git commit -a -m "synchronize from TFS"
git checkout working
git merge master

Now this deserves some more explanation. First, I make sure to commit my work into my local git repository (working branch), so everything is nice and clean. Then I switch back to my master branch, which reverts all my own changes w.r.t. the situation as it is currently on the TFS server. So I'm left with a bunch of checked out but unchanged files. Then, I can easily do a 'tf get' to get the latest version (without merge problems). After committing these changes to the git master branch, I switch back to the working branch and leverage the powerful git merge function to merge the TFS changes with my own.


After resolving possible conflicts, when I'm ready to check in my changes to TFS, I first merge my changes into master:

git checkout master
git merge working

Now I'm on my git master branch and can check in into TFS.

- page 1 of 2