Interesting. Been looking at ISSpy today to see if what I discussed here was feasible.
Spoiler: the experiment failed. But not by much.
The first part, decompiling an assembly went smoothly:
static string TestFile(string pathToAssembly)
{
//Assembly assembly = Assembly.LoadFrom(pathToAssembly);
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(pathToAssembly);
GetReferencedAssemblies(assembly);
AssemblyDefinition assemblyDefinition =
AssemblyDefinition.ReadAssembly(pathToAssembly);
AstBuilder astBuilder = new AstBuilder(new DecompilerContext(assemblyDefinition.MainModule));
astBuilder.AddAssembly(assemblyDefinition);
//new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
using (StringWriter output = new StringWriter())
{
astBuilder.GenerateCode(new PlainTextOutput(output));
string result = output.ToString();
return result;
}
}
It spat out one big long file, rather than a nice set of files, but I can live with that for now as it’s not essential at present (I’m sure the creators of ILSpy will one day add a method to do just that).
The next part, recompiling the source back into an Assembly almost worked.
The code I used to recompile the source was (forgive me for the messiness…it was just a mashup spike after all):
static AssemblyDefinition Compile(string code)
{
// <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
//<TargetFrameworkProfile>Client</TargetFrameworkProfile>
//var provider = new CSharpCodeProvider(new Dictionary{{ "CompilerVersion","v3.5" }});
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
CompilerParameters options = new CompilerParameters();
//if (TargetFramework == TargetFramework.Silverlight)
//{
// // Silverlight only: ignore the rsp file, because we want to replace the
// // default desktop .net framework mscorlib and other "default" dlls
// // with the Silverlight ones
// parameters.CompilerOptions = " /nostdlib ";
//}
//options.CompilerOptions = "/unsafe /o-";
options.CompilerOptions += " /lib:" +
string.Join(",",
new string[]
{
Environment.CurrentDirectory,
@"D:\XF.Code\CS.FF.XAct.Lib2\_CompiledAssemblies\Debug"
});
// Generate an executable instead of
// a class library.
options.GenerateExecutable = true;
// Set the assembly file name to generate.
//options.OutputAssembly = exeFile;
// Generate debug information.
options.IncludeDebugInformation = true;
// Save the assembly as a physical file.
options.GenerateInMemory = false;
// Set the level at which the compiler
// should start displaying warnings.
options.WarningLevel = 3;
// Set whether to treat all warnings as errors.
options.TreatWarningsAsErrors = false;
// Set compiler argument to optimize output.
//options.CompilerOptions = "/optimize";
// Add an assembly reference.
options.ReferencedAssemblies.Add("System.dll");
options.ReferencedAssemblies.Add("System.Core.dll");
options.ReferencedAssemblies.Add("System.Drawing.dll");
options.ReferencedAssemblies.Add("System.Xml.dll");
//Interesting -- this comes in via Attributes...and was not picked up...hum
options.ReferencedAssemblies.Add("System.Runtime.Serialization.dll");
//THis needs hints to find it (via lib switch)
options.ReferencedAssemblies.Add(@"Microsoft.Practices.ServiceLocation.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try
{
if (results.Errors.Count > 0)
{
StringBuilder b = new StringBuilder("Compiler error:");
foreach (var error in results.Errors)
{
b.AppendLine(error.ToString());
}
throw new Exception(b.ToString());
}
return AssemblyDefinition.ReadAssembly(results.PathToAssembly);
}
finally
{
File.Delete(results.PathToAssembly);
results.TempFiles.Delete();
}
}
Now…that would / should have worked, but I started to get all kinds of errors.
Took me a second to find out why it was confused.
What’s happening is stuff like this:
private static void Initialize()
{
Type attributeType = typeof (DefaultServiceAttribute);
Type[] serviceTypes = AppDomain.CurrentDomain.GetTypesDecoratedWithAttributes(attributeType);
foreach (Type serviceType in serviceTypes)
{
var defaultServiceAttribute =
serviceType.GetAttribute<DefaultServiceAttribute>(false);
_container.Register(defaultServiceAttribute.ServiceInterface, serviceType);
}
}
is getting decomplied as:
private static void Initialize()
{
Type typeFromHandle = typeof(DefaultServiceAttribute);
Type[] typesDecoratedWithAttributes = AppDomain.CurrentDomain.GetTypesDecoratedWithAttributes(typeFromHandle, true);
Type[] array = typesDecoratedWithAttributes;
for (int i = 0; i < array.Length; i++)
{
Type type = array[i];
DefaultServiceAttribute attribute = type.GetAttribute(false);
ServiceLocatorService._container.Register(attribute.ServiceInterface, type, null, false, false);
}
}
Notice the missing T after the type.GetAttribute …
Conclusion
ILSpy looks like it’s the thing I want…something to make a “Reflector as a Service” with…but will have to wait till they iron out those bugs.
But I was soooooo close!
Ref: https://github.com/icsharpcode/ILSpy/issues/287
PS: Just checked -- the issue remained in ILSpy v2.0 as of today… 
Links:
http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/b2fc6912-5fd3-428e-a86e-951a1d81bd05
http://www.nokola.com/trycsharp/HowToBuild.aspx
http://msdn.microsoft.com/en-us/library/system.windows.assemblypart(v=vs.95).aspx
http://msdn.microsoft.com/en-us/library/0k6kkbsd.aspx
http://msdn.microsoft.com/en-us/library/microsoft.build.execution.buildmanager.aspx
http://msdn.microsoft.com/en-us/library/system.codedom.compiler.compilerparameters.referencedassemblies.aspx
http://msdn.microsoft.com/en-us/library/s5bac5fx.aspx