ILogicalThreadAffinative, suite.

Posté le jeudi 15 mai 2008 04:09 par jay :: 0 commentaire(s)
Classé sous , ,

This post is also available in english here .

Dans un précédent post, je parlais d'une fonctionnalité du Framework .NET qui permet de passer des informations automatiquement d'une thread vers toute autre thread qu'elle crée.

En fait, le contexte d'appel passe non seulement aux Threads du Thread Pool, mais également à toute instance de System.Threading.Timer et aux IO Completion Threads, comme celle utilisées avec les sockets.

J'ai été surpris par le fait que dans les premiers étages du pipeline remoting coté serveur, il y avait des informations dans le CallContext et ce bien avant que le message entrant n'ai été interprété. Mais cela n'était pas tout à fait ce à quoi je m'attendais; c'était des données qui étaient présentes dans le contexte d'appel lors de l'appel à RemotingConfiguration.Configure().

Cela prend du sens, puisque tous les sockets utilisés par le TcpChannel et HttpChannel sont créés lors de l'appel à cette méthode, et des opérations asynchrones sont démarrées à ce moment la. Donc, pour éviter d'avoir les données qui transitent de l'autre coté, il y a ces deux méthodes sur la classe ExecutionContext pour supprimer et restaurer le passage du context d'appel.

IEnumerable<T>.Any() vs. IEnumerable<T>.Count() != 0

Posté le dimanche 11 mai 2008 00:15 par jay :: 2 commentaire(s)
Classé sous , ,

An english version is available here .

Après avoir lu ce post d'Eric Lippert, je me suis rappelé que dans l'exemple de ce post, j'utilise IEnumerable<T>.Count() ou je ne me sers pas vraiment la valeur de retour, et du coup, mon code énumère la totalité de la collection inutilement.

J'aurais pu utiliser IEnumerable<T>.Any(), qui après avoir regardé le code IL, démarre simplement l'énumération et s'arrête juste après un élément puis retourne true, ou si il n'y a rien, retourne false.

Bien plus efficace, à défaut d'utiliser PLinq !

Aventures avec le mot clé "let" dans LINQ to Objects

Posté le samedi 10 mai 2008 17:35 par jay :: 3 commentaire(s)
Classé sous , ,

This post is also available in english here .

Je me suis finalement décidé à blogger dans les deux langues, français et anglais. BlogEngine.NET ne me permet pas d'écrire mes posts dans les deux langues, et après avoir fait quelques essais de site multilingue sur la même url, il se trouve que Google n'indexe pas vraiment très bien ce genre de contenu dynamique.

Quoi qu'il en soit, j'ai eu le temps dernièrement de jouer avec LINQ to objects, et en particulier avec le mot clé "let".

J'avais un grand nombre de fichiers XML placés dans des répertoires multiples, et je voulais les filtrer avec une expression régulière. D'abord, voici comment j'ai récupéré tous les fichiers dans mes répertoires :

  var files = from dir in Directory.GetDirectories(rootPath, SearchOption.AllDirectories)
              from file in Directory.GetFiles("", "*.*")
              select new { Path = dir, File = Path.GetFileName(file) };

Arrivé à ce point, j'aurais pu éviter d'utiliser Directory.GetDirectories puisque GetFiles permet également de chercher recursivement. Mais puisque GetFiles ne retourne qu'un seul tableau de String et non un énumérateur, cela aurait voulu dire que tous mes fichiers auraient été retournées en un seul tableau, ce qui n'est pas très efficace en terme de consommation mémoire. J'aurais préféré avoir une implémentation de GetDirectories et GetFiles basée sur un itérateur, mais la plus fine énumération ne peut être faite que comme ca, sans appel vers du code natif.

Ensuite, ayant tous mes fichiers, je voulais à présent les filtrer en utilisant une expression régulière, puisque les fichiers que je voulais analyser suivaient un format de nom spécifique. J'ai donc mis à jour ma requête comme suit :

    Regex match = new Regex(@"(?<value>\d{4}).xml");
    var files2 = from dir in Directory.GetDirectories(args[0], "*", SearchOption.AllDirectories)
                 from file in Directory.GetFiles(dir, "*.xml")
                 let r = match.Match(Path.GetFileName(file))
                 where r.Success
                 select new {
                    Path = dir,
                    File = Path.GetFileName(file),
                    Value = r.Groups["value"].Value
                 };

Cette fois, j'ai introduit le mot clé let. Ce mot clé est intéressant puisqu'il permet la création d'une variable locale à la requête qui peut contenir à la fois des collections ou des objets simples. Le contenu de cette variable peut être réutilisé dans la clause where, comme source d'une autre requête from, ou dans le select.

Dans mon cas, je voulais simplement avoir le résultat de l'évaluation de mon expression régulière, donc j'ai simplement appelé Regex.Match pour valider le nom du fichier. Enfin, je place le contenu d'un groupe de l'expression dans le type anonyme résultant.

Avec tous mes fichiers filtrés, j'ai constaté ensuite que certains n'étaient pas valides puisqu'il ne contenaient pas un noeud XML spécifique. J'ai adapté ma requête comme cela :

    var files2 = from dir in Directory.GetDirectories(args[0], "*", SearchOption.AllDirectories)
                 from file in Directory.GetFiles(dir, "*.xml")
                 let r = match.Match(Path.GetFileName(file))
                 let c = XElement.Load(file).XPathSelectElements("
//dummy")
                 where r.Success && c.Count() != 0
                 select new {
                    Path = dir,
                    File = Path.GetFileName(file),
                    Value = r.Groups["value"].Value
                 };

J'ai ajouté un nouveau let pour me permettre de charger le document XML, et m'assurer que le noeud nommé "dummy" existe quelque part dans le codument. Au passage, si vous cherchez XPath dans XLinq, regardez par ici.

Vous vous demandez peut-être quand le XElement.Load est effectivement évalué... et bien il n'est sulement évalué lors de l'appel du c.Count(), qui ne l'est que lorsque la regex a validé le fichier concerné. De cette manière, je ne suis pas en train d'essayer de charger tous les fichiers retournés par GetFiles. Il faut se rappeler que les requêtes LINQ ne sont évaluées que lorsqu'elles sont énumérées.

En conclusion, LINQ est une technologie particulierement intéressante, et définitivement pas seulement réservée pour l'interrogation de bases de données. Ce que j'apprécie le plus et qu'il est possible d'écrire du code pratiquement sans boucles, ce qui permet de réduire les effets de bord.

Si vous n'avez pas jeté un coup d'oeuil sur LINQ, essayez, vous aprécierez probablement !

.NET Threads, CallContext et ILogicalThreadAffinative

This post is also available in english here .

J'ai récemment cherché un moyen de passer automatiquement des informations du contexte d'appel d'une thread vers tout autre thread créée à partir de la première. Cela peut-être utile pour de multiples raison, comme par exemple avoir des informations contextuelles placées dans le TLS à propos de l'utilisateur courant, ou pour tout autre information contextuelle spécifique à l'application.

Il est possible d'obtenir ce comportement en entourant le point d'entrée d'une thread de code qui va passer les informations à la nouvelle thread. C'est généralement assez fastidieux, voire complexe lorsqu'il s'agit de passer des informations générées en interne par un framework, puisqu'il faut absolument intercepter toutes les créations de thread.

Il existe un moyen pour faire cela en utilisant la class CallContext, et en particulier les méthodes GetData/SetData. Le problème est que si l'on place des données dans le CallContext, elles ne seront pas passées à une nouvelle thread. En pratique, pour que les données soient passées, il suffit que l'objet placé dans le CallContext implémente l'interface ILogicalThreadAffinative.

C'est une sorte d'interface marqueur qui permet d'éviter de faire transiter des données entre Threads lorsqu'elle n'y sont pas destinées.

Il est également intéressant de noter que les types marqués avec ILogicalThreadAffinative seront passés aux threads créées par le Thread Pool, et donc aux delegates placés dans la queue par l'appel à la méthode BeginInvoke qui est générée par le compilateur C#.

Enfin, dans le cas d'un appel distant en Remoting, tout type marqué avec ILogicalThreadAffinative sera sérialisé vers le contexte d'appel distant, puis sérialisé à nouveau en retour vers le contexte local.

Etre capable de faire du pas-à-pas dans le code du Framework a été d'une grande aide pour comprendre tout cela ;)

Mon autre blog...

Comme j'écris principalement en anglais, je me suis décidé à le déplacer sur mon propre site à cette adresse : www.jaylee.org

Je continuerais peut-être à poster quelques articles en francais ici, mais beaucoup moins souvent.

En ce moment, il s'agit principalement des mes pensées sur WPF, avec lequel je m'amuse beaucoup :)

See you around !

ODP.NET 10.2.0.2.20 Connection Pool Race Condition

Aaah, les joies d'Oracle. Ma base de données préférée... accompagnée de son cortège de bugs...

Bon, j'arrête là le sarcasme, mais j'ai du mal :)

Dans le cadre d'un projet sur lequel je travaille, je suis tombé sur un bug très, très gênant : Le provider ODP.NET d'oracle peut se connecter à un schéma sur lequel il n'est pas censé se connecter...

Je m'explique : dans le même AppDomain d'un même process, je crée dans des Threads différentes deux OracleConnection avec deux chaines de connexion différentes. Jusque là , rien d'anormal. Le problème est que de temps à autres, l'une de deux connexion va utiliser la chaine de l'autre thread !

Après avoir vérifé rapidement le contenu de l'objet OracleConnection, il se trouve qu'une variable nommée "m_InternalConStr" contient parfois une chaine qui ne correspond par du tout à celle qui a été passée en paramètre dans le constructeur... C'est très génant, car si l'on se connecte à une base alors que l'on pense se connecter à une autre, ... je vous laisse immaginer les dégats si on fait des updates.

Donc après de nombreuses tentatives, je suis arrivé à la conclusion qu'il faut synchroniser tous les appels à OracleConnection du constructeur jusqu'à Open avec un Mutex, et cela sur l'AppDomain courant. Vous imaginez aisément le goulot d'étranglement. J'aurais tout aussi bien pu désactiver le Connection Pool, mais la aussi, coté performance cela devient gênant.

Bien entendu, ce genre de problème apparait plus souvent sur une machine Multi Processeur. (En production dans mon cas, ca fait toujours plaisir...)

Je n'arrive pas à reproduire la Race Condition de manière systématique, mais je met avec ce post un exemple de code qui teste tout ca. Généralement, l'erreur apparait au bout de quelques essais. Pour tester si le ConnectionPool est consistant, j'effectue quelques lignes de Reflection pour aller chercher des variables interne... pas très propre, mais c'est suffisement déterministe.

Si quelqu'un se sent suffisement motivé pour tester... :)

Bluetooth Remote Control 0.5.0-Beta5

Voici une nouvelle version de Bluetooth Remote Control for Windows Mobile, avec quelques petites améliorations :

  • L'installation du fichier CAB automatique,
  • Correction de quelques problèmes de stabilité sur SPV E200,
  • La possibilité de visualiser les notes d'un slide PowerPoint sur le PPC/SmartPhone.

La version 0.5.0-Beta5 est disponible ici :

http://jaylee.org/remotecontrol

--

Here is a new version of Bluetooth Remote Control for Windows Mobile, with some improvements :

  • Automatic installation of the CAB file,
  • The correction of some stability issues on SPV E200,
  • The ability to view slide notes in PowerPoint on the PPC/SmartPhone.

The version 0.5.0-Beta5 is available here :

http://jaylee.org/remotecontrol

C# 3.0, a sneak peek

If you've used both DataSet and DataTable, you must have seen the DataTable.Select method. This is an interesting method that allows to select rows using a set of criterias, like IS NULL and comparison operators referencing columns of the current table, as well as columns from other tables using relations. The problem with method is that is returns a DataRow[], on which you cannot perform an other select.

The solution is actually quite simple : Just copy the rows you'll answer me. Yes, but you can't just reference rows in two DataTable instances, so you also have to perform a deep copy of the rows. So, with a little digging in the DataTable methods, here is what you get :

public static DataTable Select(DataTable table, string filter, string sort)
{
   DataRow[] rows = table.Select(filter, sort);
   DataTable outputTable = table.Clone();

   outputTable.BeginLoadData();

   foreach(DataRow row in rows)
      outputTable.LoadDataRow(row.ItemArray, true);

   outputTable.EndLoadData();
   return outputTable;
}

Clone is used to copy the table schema only, BeginLoadData/EndLoadData to disable any event processing during the load operation, and LoadDataRow to effectively load each row. This seems to be a fairly fast way to copy a table's data.

Now, I wondered how they would do this in C# 3.0, since there is a lot of data manipulation with the new LINQ syntax. This version is quite interesting because instead of evolving the runtime, they chose to upgrade only the language by adding features that generate a lot of code under the hood. That was the case in C# 2.0 with iterators and anonymous methods. C# 1.0 also had this with foreach, using or lock for instance.

In the particular case of Linq, C# 3.0 generates a method invocation list  of a LINQ query, producing standard C# 3.0 code with the help of lambda expressions. For example, these two lines are equivalent :

   var query = from a in test where a > 2 select a;
   var query2 = Sequence.Where(test, a => a > 2);

This ties a little more the compiler to the system asssemblies, but this does not matter anymore.

By the way, you can apply queries to standard arrays and join them :

static void Main(string[] args)
{
   var names = new[] {
      new { Id=0, name="test" },
      new { Id=1, name="test1" },
      new { Id=2, name="test2" },
      new { Id=4, name="test2" },
   };

   var addresses = new[] {
      new { Id=0, address="address" },
      new { Id=1, address="address1" },
      new { Id=2, address="address2" },
      new { Id=3, address="address2" },
   };

   var query = from name in names
      join address in addresses on name.Id equals address.Id
      orderby name.name
      select new {name = name.name, address = address.address};

   foreach(var value in query)
      Console.WriteLine(value);
}

I've joined the two arrays using the Id field, and creating a new type that extracts both name and address. I really like inline querying because you can query anything that implements IEnumerable.

I'm also wondering how it'll fit into eSQL (Entity SQL)...

But back to the original subject of this post. They had to do some kind of a DataTable copy in the C# 3.0 helper library, which uses extension methods :

   DataTableExtensions.ToDataTable<T>(IEnumerable<T>)

And with some further digging, I found that the LoadDataRow method for copying data is the fastest way to go.

I also found out using the great reflector that there is an Expression compiler in System.Expressions.Expression<T>. Maybe they finally did expose an expression parser that we can use... I'll try this one too !

SourceSafe and Explicit Error Messages

Aaaahhh, Visual SourceSafe, my favorite software. Maybe more than Toad. Especially when I get the most explicit and out of context message "File not found" during an archive restore using the admin GUI tool. That reminds me of the unix-style error messages... What a mess.

Anyway, if during a SourceSafe archive restore you get that error and you've already done more than once a full analyze of your source base, then you might want to try the command line utility ssrestor to do this.

Yeah I know, Florent, I'd better switch to Team System, but beleive me I'm trying :)

First thoughts on Windows Vista CPP Beta 2

Windows Vista Beta 2 has been released a few weeks ago, and I though it was about time for me to give it a try.

Clean installation has been pretty long, mainly because I've burnt the OS ISO Image on a DVD-RW disc, which is not particularly fast. It almost took an hour to complete, but after that the machine is usable. Almost no user input, just at the beginning for the partitions, locale and Product Key and again at the end for the locale.

I'm testing on a Dell Latitude D820 with a NVidia Quadro 120M, and the official drivers from NVidia do not support this one. However, with a little bit of tweaking in the inf file of the driver, Vista is able to enable the sleek Aero glass UI, which is pretty neat ! I like to be able to look through the taskbar, and to use the 3D task switcher. It's also interesting to see pixel shaders in action on something else but a game. I'm a little bit curious to see what kind of UI graphic designers are going to create... Imagine something like a fish tank around your windows :) Ok, that'd be pretty annoying, but you get the picture.

This build of Windows Vista includes the Windows Media Center. This is a cool peace of software but there are some bugs left, like the mouse not in synch with the actual clicks on the screen, or the Aero look disapearing for a while when a run it on my second screen. I don't know who to blame for the latter, but I think it would be because of my hack around the video driver.

The system is pretty responsive, even with the Aero UI enabled. I'd have expected it to be far less responsive considering the whole bunch of new features pressuring the system. It still has some slowdowns here and there, but I can't figure out why. Vista features ReadyBoost, which allows the system to "cache" the page file on a USB Flash Drive. Since a flash drive is about 10 times the speed of the hard drive, it speeds up the read of evicted memory pages. With this feature enabled, I find the system more responsive and applications are returning far more rapidly. I'll be trying to do some charts on overall system speedup. Intel SpeedStep is also natively used, the processor frequency is changing when the cpu usage increases.

I also had some bluescreens during the boot, and with the help of WinDBG, I figured out it was the USB driver that was faulty. Not that it actually is the USB driver, but rather the USB Audio driver I have that is messing up the system. It's not a Windows Vista compliant, so I'm not surprised...

Also around system performance, Vista maintains a performance index, which allows to see if system performance, like booting, is degrading, steady or improving. It also gives you what kind of device driver slows the boot or standby process, and an history of the changes on the system.

About mouting ISO images, Daemon Tools 3.33 - the latest version crashes the system - allowed me to install Visual Studio 2005, and SQL Server client tools SP1, which also both run fine. The only application that does work as well as on XP is VLC, which forces Vista to fall back in visual compatibility mode where aero is disabled. I'll try to talk about applications compatibility in a future post.

Mass storage does not seem to have changed at lot, though there is now the possibility to shrink or extend online partitions. When you shrink a volume, it only allows you to remove the free space at the end of the volume, and does not seem to defragment or compact it. Anyway, a long time missing feature...

Networking seems to have improved a lot under the hood, for what I can read about. The only part that held my eyes is the IPv6 support with, for the first time, a UI to configure it. Wifi's working like a charm.

On the mobile side, the "so-called" Windows Mobile Device Center is nothing more than ActiveSync in disguise. Dialogs are a prettier, but I really hope this will not stay the same crap it is now.

Last, the Windows Explorer has a lot of improvements, like the copy files dialog which now gives an optional throughput in MB/s and total size, or easy file filtering in the column headers. There is also a feature that allows to fully or partially restore a previous version of a folder. This is a really interesting feature that kind of legitimates a 500GB hard drive for a secretary computer ;) It will certainly bring out some security problems, but it's nice it exists.

 

Overall, I'm neither amazed nor disapointed in Windows Vista. I've read that the latest build fixes a lot of the slowness, and on a Core Duo 2.0GHz, to my perception, it does not run as fast as XP does. I'll wait for the RC1 to fix my mind :)

BTRemote Control and Windows XP 64 Bits

Quite a few people have now been using the latest beta for a while, and I get most of the time feature requests, sometimes non critical bugs like the Remote Client not connecting if the host PC is not discoverable, and not so often blocking bugs.

The one Krijn Wijnands (thanks !) has uncovered might involve Windows XP 64 Bits. The remote client does not connect to the server, and he's using an hardware configuration that's proved to work fine.

I do not own a 64 bits machine and if any of readers of this blog or user of this utility uses Windows XP 64 bits, please leave me a message. I'll be glad to hear from you.

The client version of this software do log much out of the debug build for now, but I'll add some more for extensive diagnostics.

From a pure developer point of view, .NET 2.0 64 Bits should not change a thing, but I suspect a P/Invoke issue that I've not covered. That should give me a reason to upgrade my server to 64 Bits ;) For the sake of the testing, of course.

For the next release, I'll be adding generic support for applications, configurable using a static xml file (there's no point on modifying this at runtime)

If you have some other wishes that come to mind, feel free to speak !

Long time, no see !

I know, it's been a while. Schedule's been hard to catch up to, but I now get enough time to blog a little... So here are some news about what I did the past several months:

  • A new release of Bluetooth Remote Control for Windows Mobile, which now supports QVGA screens, and uses a lil' bit of .NET 2.0 on the desktop. It is still in beta phase, since there's been a lot of changes under the hood. I've had some testers running it with QTEK 9100/Orange M3000 (HTC Wizard clones) and SPV C600. So far, a few bugs reported, and feature requests like support for the Windows Media Center. About the latter, since I've been playing with the Beta2 CPP of Windows Vista, I'll be adding support for this one, hoping it'll work with previous releases.
  • Still playing with my Terratec T² (a DVB-T tuner), trying to build some kind of an RTSP server, broadcasting on my LAN using multicast. I've been able to multicast a DVB-T multiplex on my network, playing it back with VLC. I even got to play both H264 Test HD1 and Test HD2 streams (10.5 mpbs each, compared to the 5mbps of SD streams). Though, I had a hard time changing the tuning frequency, mainly because the Terratec BDA driver seems to need a full DShow graph set up, needing MPEG-2 filters that I don't use anyway, which took me time to figure out.
  • I also worked on a project to correlate GSM antennas to GPS coordinates, a lot like CellTrack, the original idea being the software mostly on .NET and working on my QTEK 9100. This also led me to use the GPS API provided by Windows CE 5, which works pretty well, except when the GPS loses its power and sorta freezes the underlying serial GPS stack. Anyway, worth a look if you don't want to decode NMEA sentences by hand.
  • Finally, I'm working on the remote reading of water meters for Suez-Environment. Quite an interesting project which involves processing a important amount of data coming from water meters.

That's it for now :)

I'll certainly be blogging a bit more about the Remote Control software, since this is what I'm motivated the most to work on right now.

Precision Timer in .NET 2.0

If you've been using the .NET Framework since the beginning, you must have had to do some early code profiling, or framerate computation for realtime graphics.

The first idea that pops up to acheive this is to use the DateTime.Now property and do some subtraction of two instances. This is not a good idea since the resolution of this timer is around 10ms or so, which is clearly not enough (and your framerate counter may not go higher than 100 FPS or worse may not work at all).

If you've been in the business for long enough, and been doing some plain old "native" code in, say, C++ on Win32, you should probably used the couple QueryPerformanceFrequency/QueryPerformanceCounter to get the job done. And the same goes for .NET 1.0/1.1. Well, I don't know for you, but each time I have a project that reaches a certain critical size, I always need to use this kind of timer and I end up by writing the P/Invoke wrapper to reach these two methods.

Good news is, .NET 2.0 already has this class integrated in the form of System.Diagnostics.Stopwatch, so you don't have to write it from scratch again and again because you can't find on the net the right "free" class that does enough for you.

The BCL team has added some other nice utility classes like this one, and this saves quite some time.

Moving my Blog around...

Hi everyone,

I'm moving my blog here at CodeS-SourceS, since Florent Santin (and the admin I don't know, thanks btw) has been kind enough to give me a blog here. All my previous posts are still there, but I'll now be posting here.

Since I'm a .NET enthusiast, most of my posts are and still will be around .NET, C# 2.0 and 3.0 (and not VB.NET), the .NET Compact Framework I used to develop Bluetooth Remote Control, and some other stuff I'm working on.

Right now, my focus is mostly on .NET 2.0, its generics, anonymous methods, iterators and LCG to get the most out of it.

I'll also post about a litte utility I'm working on to have a clone of the nice CellTrack software for the SPV C500/C600 to work on the HTC Wizard clones (M3000, QTEK 9100, IMate K-Jam). It's now working quite nicely, especially when coupled with a GPS receiver...

Anyways, stay tuned for more .NET stuff :)

IIS, HTTP 401.3 and ASP.NET directories ACLs

A few days ago, on a newly installed web server with all the appropriate security patches applied, I kept having the same error on every ASP.NET 1.1 application I was running :

HTTP Error 401.3 - Unauthorized: Access is denied due to an ACL set on the requested resource.

At first, the reflex is to check all the permissions of the mapped physical directory, that they match the Application Pool identity, the guest identity (IUSR_Machine on my server) and for some configurations, the impersonated identity any ASP.NET configuration. Even with all these checks, any ASP.NET application was returning the same 401.3 error for anonymous users...

Well, it turns out that the ACL of the %SystemRoot%\Microsoft.NET\Framework\v1.1.4322 is important too... I don't know how the ACL got changed in the first place, and I don't know either how I came to check on these ACL, but that can waste a lot of time...

Sharing Visual Studio 2005 Settings.settings File across Assemblies

A new feature of the Visual Studio 2005 is the introduction of the Setting.settings file, which generates a class that maps your application configuration file. This avoids creating this class by yourself, and it supports updating and saving. What is is more interesting is that WebServices automatically add their WSDL locations in there, as well as data connection strings.

There is a problem though when you let VS2005 create the file by itself in a multi-assembly setup, where it creates a settings.settings for a "dll" packaged assembly. You end up with one settings.settings file for each of your assemblies, which is particularily not useful.

So, because there's a solution, you just have to share the only settings.setting file that matters to your application and here's how :

  • Remove the settings.settings file from all your assemblies, except the one that will be the master.
  • Add the master settings.settings file as a linked file in each of your projects, and you're done.

Just in case you've never linked a file in VS, when you're about to add the file to your project, just click on the little arrow next to the open button and select Link File. The magic after this is that VS2005 uses the linked file as if it were a local file.

One last note : Don't forget to copy all your existing settings from each assemblies to your master settings file.

Reflective Visitor vs. Meta Visitor

In a previous post, Johan explained us how he managed to get the visitor design pattern to work without having to redefine visitable methods in the visitor base class. This is quite interesting for some reasons :

  • This is the edge of C++ programming, few know how to use templates like this,
  • The choice of the method to execute is done at compile time, avoiding the runtime type checking implied with the Reflective version and this is good for speed of code execution.

However, there are a few issues. The Meta Visitor does not handle passing parameters like the Reflective one does. Even if it did, I expect the templated code to dramatically increase to a point where a normal human beeing is having a hard time reading it, along with giving a really hard time for the compiler to get to the end of it...

Anyway, I'm pretty confident about Johan ending up with a longer blog with a solution to this issue. (No stress Proppy, really :))

I'm a pragmatic developer, I try to consider all the aspects of the development and I tend to prefer readability over technically challenging code. But there's a place for everyone and researchers are here to make things go further away... Go, Go, Go proppy ;)

C# 2.0, Closures and Anonymous Delegates

I was looking around the web about new features in C# 2.0, and I came across this article about the support for closures in C# 2.0. The article explains that the support for closures in C# 2.0 takes the form of anonymous delegates.

There are some examples of closures like this one :

public List<Employee> Managers(List<Employee> emps)
{
  return emps.FindAll(
    delegate(Employee e)
    {
      return e.IsManager;
    }
  );
}

Which is interesting, but less than this one :

public List<Employee> HighPaid(List<Employee> emps)
{
  int threshold = 150
;
  return emps.FindAll(
    delegate(Employee
e)
    {
      return
e.Salary > threshold;
    }
 
);
}

The interesting part here is that the delegate is actually allowed to use a variable that is local to the method where it is defined. You might wonder how this is implemented by the C# compiler.
It may become even less obvious with this example :

public Predicate<Employee> PaidMore(int amount)
{
  return delegate(Employee e)
  {
    return e.Salary > amount;
  };
}

Ok, where does the compiler stores the value of "amount" since the delegate method is only returned to be executed later... ?

In fact, the compiler only generates a "DisplayClass" that containts amount as a field initialized when the anonymous delegate is created, and the implementation of the delegate itself.

Easy.

Reflective Visitor using C#

There is a well known design pattern in the Object Oriented world: The Visitor pattern.

This pattern, among other things, allows to extend an object without actually modifying it. It is fairly easy to implement in any good OO language such as C++, Java or C#.

However, there is a problem with the implementation of this pattern, or rather an implementation limitation. It requires the base interface or abstract class for all visitors to define at most one method for each type that may visit it. This is not a problem by itself, but it requires to modify the visitor base each time you add a new type. The best way to do this would be to call the appropriate method based on the caller type.

.NET provides that kind of behavior through reflection, as it is possible to find a method based on its parameters at runtime.

I decided to try this out with the C# 2.0 and its generics :)

Here what I came up with :

public interface IOperand
{
 
IOperand Accept(Visitor visitor, IOperand
right);
}

public class Operand< T> : IOperand
{
  private
T _value;

  public
Operand(T value)
 
{
   
_value = value;
 
}
  public IOperand Accept(Visitor v, IOperand
right)
 
{
    return v.Visit(this
, right);
  }
  public T Value
  {
    get { return
_value; }
 
}
  public override string ToString()
  {
    return string.Format("{0} ({1})", _value, GetType());
  }
}

This is the definition of an operand, which is used in a abstract machine to perform operations on abstract types. This class is generic, I did not want to implement all the possible types.

Then here is the visitor :

public class Visitor
{
 
public virtual IOperand Visit(IOperand left, IOperand right)
 
{
   
MethodInfo info = GetType().GetMethod("Visit", new Type[] { left.GetType(), right.GetType() });
   
   
if (info != null && info.DeclaringType != typeof(Visitor))
     
return info.Invoke(this, new object[] { left, right }) as IOperand;

    
Console.WriteLine("Operation not supported");
   
return null;
  
}
}

This method search in the current type all methods named "Visit" that take the actual type of the parameters left and right and tries to match a method with it. Also, to avoid looping through the same method we're in since it's matching everything, there is a test for the type declaring the method.

Now the AdditionVisitor :

public class AdditionVisitor : Visitor
{
  public IOperand Visit(Operand<int> value, Operand<int> right)
  {
    return new Operand<int>(value.Value + right.Value);
  }
  public IOperand Visit(Operand<int> value, Operand<short> right)
  {
    return new Operand<int>(value.Value + right.Value);
  }
  public IOperand Visit(Operand<double> value, Operand<int> right)
  {
    return new Operand<double>(value.Value + right.Value);
  }
}

Which defines a bunch of visitable methods used to add different operations on IOperand-like types.

And finally to use it :

class Program
{
  static void Main(string[] args)
  {
    Operand<int> a = new Operand<int>(21);
    Operand<short> b = new Operand<short>(21);
    Console.WriteLine(Add(a, b));
  }

 
static IOperand Add(IOperand a, IOperand b)
 
{
   
AdditionVisitor addVisitor = new AdditionVisitor();
   
return a.Accept(addVisitor, b);
 
}
}

Using this Reflective Visitor, modifying the base visitor class is not needed anymore, which limits the modifications to one class only. Of course, there's room for optimization, for instance by avoiding the method lookup using the System.Reflection namespace, but you get the picture.

Some asked me what could be done in .NET that could not be done in C++, this is an example of it :)

Playing with C# 2.0 generics

While generics is interesting, the concept is mostly applied to classes. This is generally good, and in the .NET Framework 2.0, you can find a lot of classes that are built around this, like generic lists, dictionaries, Queues, ... A lot alike what can be found in the C++ STL.

But there is another interesting feature with generics : It can also be applied to methods in non-generic classes and interfaces.

I'm currently developping a new version of an internal Epitech Instant Messenger client which will run using .NET 2.0, and I'm trying to heavily use plugins. I'm going to skip the part about the plugins but, there is a point that is interesting. When a specific plugin wants to get an instance of an other plugin by using its interface type as an identifier, using .NET 1.1, I would have done something like this :

    IContactList contactList = _core.GetPlugin(typeof(IContactList)) as IContactList;

The code is pretty easy to read. I'm trying here to get an instance of a IContactList plugin and use the as operator to avoid an exception if the plugin cannot be found.

But there is too much IContactList involved here. Ok, you'll tell me "Well, this is not a critical part of the application so, who cares ?". Well, I'm gonna tell you that I'm looking for the simplest user exposed code. So, using the .NET 2.0 generics features, I'm writing something like this :

    IContactList contactList = _core.GetPlugin<IContactList>();

This is pretty much the same, but I've avoided writing IContactList twice and an as operator.

Overall, I haven't gained anything but less code to read. I don't gain anything in the type checking speed area, since I'm still doing an upcast in the GetPlugin method. By the way, here's what this method looks like :

    public T GetPlugin< T>() where T : IPlugin
    {
     
foreach (IPlugin plugin in _manager)
      {
       
if (plugin.GetType().GetInterface(typeof(T).FullName) != null)
       
{
         
return (T)plugin;
       
}
     
}

     
return default(T);
    }

I've also discovered a new use of the default keyword, which is used here to generate a default value for a type. If it's a value type, it's zero and if it's a reference type, it's null. I've also used the where clause, which forces the user of the GetPlugin method to specify a type that implements IPlugin prior to the call.

All this is interesting... I got used to the fact that I have to use general purpose collections and methods, but now C++ template reflexes are coming back ;) This is gonna be fun !

Plus de Messages Page suivante »

Les 10 derniers blogs postés

- Disparition de variables de session PHP après une redirection ? par MadMatt le il y a 9 heures et 46 minutes

- [MOSS 2007] Publier ses formulaires InfoPath via feature par Adrien Siffermann le il y a 12 heures et 53 minutes

- Imagine Cup 2008 - Paris - Les résultats par TheSaib .NET blog le il y a 14 heures et 15 minutes

- L'Egypte accueille Imagine Cup 2009 par Code is poetry le il y a 14 heures et 27 minutes

- PowerShell : Mise en ligne de fonctions intéressantes pour SharePoint par Blog Technique de Romelard Fabrice le il y a 15 heures et 34 minutes

- Raccourcis clavier et CRM 4 par Clark, C#, MSCRM, SBS le il y a 19 heures et 40 minutes

- [Silverlight] Comment échanger des données entre une application Silverlight et une page ASP.NET via cookies ? par Thomas Lebrun le il y a 20 heures et 16 minutes

- SharePoint 2007 : Trouver les fichiers CheckOut dans une librairie de document par Philippe Sentenac [MVP SharePoint] le il y a 22 heures et 44 minutes

- [Open XML] Travailler avec Open XML : Linq To XML (Partie 2 - Requêtes/XPath) par Julien Chable le 07-08-2008, 02:05

- [Open XML] Travailler avec Open XML : Linq To XML (Partie 1 - Namespace) par Julien Chable le 07-08-2008, 00:44