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… Sad smile

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