How to Change Namespace of .NET Assembly?
As you know, one of the peculiarities of Lokad.Shared.dll (of Shared Libraries) is that it integrates into the System namespace, transparently providing some helpers and extensions that .NET framework does not have, yet.
However, this might feel uncomfortable if you want to use libraries just a for the retry policies, business rules or any other minor piece (thanks to Jeremy Gray for pointing this out).
So in order to deal with this we need some process that would create a copy of assemblies where all classes are moved from System.* to Lokad.*.
Well, it does not have to be more complex than that:
var codebase = new Codebase("Lokad.Shared.dll");
foreach (var type in codebase.Types)
{
type.Namespace = type.Namespace.Replace("System", "Lokad");
}
codebase.SaveTo(output);
That's all you need to move all type definitions in the library from the System* namespace to Lokad* namespace.
Since Lokad.Shared.dll has got a strong name, we just need to perform one more step and resign the assembly (SharedKey.snk is available in the trunk):
sn.exe -Ra Lokad.Shared.dll SharedKey.snk
If we want to migrate multiple assemblies at once, we've got to update their type references as well. Here's how this could be achieved:
var codebase = new Codebase(assemblies);
var changes = new Dictionary<string, string>();
foreach (var type in codebase.Types)
{
var oldName = type.FullName;
type.Namespace = type.Namespace.Replace("System", "Lokad");
if (type.IsPublic)
{
changes.Add(oldName, type.FullName);
}
}
foreach (var type in codebase.GetAllTypeReferences())
{
if (changes.ContainsKey(type.FullName))
{
type.Namespace = type.Namespace.Replace("System", "Lokad");
}
}
codebase.SaveTo(output);
Now, wouldn't it be nice to have XML file updated as well, so that IntelliSense could display helpful hints? It is really simple to achieve this:
var docs = assemblies
.Convert(a => Path.ChangeExtension(a, "xml"));
foreach (var fileName in docs)
{
var text = File.ReadAllText(fileName);
var builder = new StringBuilder(text);
foreach (var pair in changes)
{
builder.Replace(pair.Key, pair.Value);
}
var newPath = Path.Combine(output, Path.GetFileName(fileName));
using (var writer = File.CreateText(newPath))
{
writer.Write(builder.ToString());
}
}
This simple process has just been integrated into the build script of Lokad Shared Libraries. If somebody prefers to keep their System namespace clean of helper classes and contextual extension methods - just grab the download with "Lokad namespace" mark in it.
PS: Snippets above leverage latest version of Lokad.Quality.dll from the same project.
Friday, January 30, 2009 at 18:51
Reader Comments (3)
Forgive my ignorance, but is this Cecil that you are rewriting the assembly with? In any case, that's a very slick solution you have there.
Exactly.
Lokad.Quality is just a set of helper extensions and classes on top of Mono.Cecil.
I figured that was the case, but hadn't had a chance to dig into it myself to be sure. Thanks again for the quick turn-around on the namespace-adjusted version of the library. I have switched us over to that from our custom build and the ActionPolicy pieces that we were in need of are working wonderfully. Thanks yet again for the library itself. Lots of great stuff in there waiting to be found! :)