Reflector .NET to C# Decompiler Tests
Reflector is a .NET browser with an integrated C# decompiler. It will also display the code "translated" into Visual Basic or Delphi, or disassembled as IL. Reflector does not save an entire file of code to write to a source file; I had to add the text in bold to the given output.
Fibo
For source, see
DecompilerFiboDotNetSource. Decompiled source from Reflector:
using System;
class Fibo {
private static int fib(int x)
{
if (x > 1)
{
return (Fibo.fib((x - 1)) + Fibo.fib((x - 2)));
}
return x;
}
public static int Main(string[] args)
{
int num2 = 0;
try
{
num2 = Convert.ToInt32(args[0]);
}
catch (Exception)
{
Console.WriteLine("Input error");
return 1;
}
int num1 = Fibo.fib(num2);
Console.WriteLine("fibonacci({0}) = {1}", num2, num1);
return 0;
}
}
The source code compiles and runs with no modifications (other than inserting the 3 bolded lines).
Casting
For source, see
DecompilerCastingDotNetSource. Here is the output from Reflector:
using System;
class Casting {
public static void Main(string[] args)
{
char ch1;
char ch2;
for (ch1 = '\0'; (ch1 < '\u0080'); ch1 = ch2)
{
Console.WriteLine("ascii {0} character {1}", ch1, ch1);
ch2 = (ch1 + '\x01');
}
}
}
The main cast is missing in the WriteLine statement. The line
ch2=(ch1 + '\x01');
needs a cast to
(char)
.
When both these changes are made, the program compiles and runs correctly.
The for loop is reconstructed correctly, although the increment clause is imlemented a little strangely.
Inner Classes
For source, see
DecompilerInnerClassesDotNetSource. When decompiled with Reflector,
the functions and hierarchy appear correct,
but is tedious to piece together from the individual functions (and constructors).
The names are
not initialised.
The print_names function decompiles as follows:
public void print_names() {
Console.WriteLine(this.name);
}
The
this.
is not needed.
Sable Test Program
For source, see
DecompilerSableDotNetSource.
Here is the output from Reflector:
public static void f(short i)
{
Circle circle1;
Drawable drawable1;
Rectangle rectangle1;
bool flag1;
if (i > 10)
{
rectangle1 = new Rectangle(i, i);
flag1 = rectangle1.isFat();
drawable1 = rectangle1;
}
else
{
circle1 = new Circle(i);
flag1 = circle1.isFat();
drawable1 = circle1;
}
if (!flag1)
{
drawable1.draw();
}
}
public static void Main(string[] args)
{
MainClass.f(11);
}
I could not find a way to reproduce the class definitions readily.
All the information is there, it would just be tedious to reconstruct.
To be fair, Reflector is not designed to be a decompiler, just a browser.
When the class definitions for Circle, Rectangle, and Drawable were included,
the program compiled correctly.
Simple Control Flow
For source, see
DecompilerControlFlowDotNetSource. Here is the output from Reflector:
public static int foo(int i, int j)
{
int num1;
Label_0000:
try
{
while ((i < j))
{
j = num1;
i = (j++ / i);
}
}
catch (Exception)
{
i = 10;
goto Label_0000;
}
return j;
}
public static void Main(string[] args)
{
Foo.foo(2, 3);
}
The output does not compile, because there is an assignment to an uninitialised variable (num1).
When this is commented out, the program compiles.
The do while with continue is handled with a goto, which is arguably not as easy to read.
Image Viewer
For source, see
DecompilerImageViewerDotNetSource.
This program was compiled with a Microsoft compiler, and so should be easy to decompile.
I did not have the libraries to compile this program, however, it appeared to decompile
without incident. As an example, here is the function that gave Salamander and Anakrino
problems:
private static Pixbuf GetPixbufFromFile(string filename)
{
Pixbuf pixbuf1;
Pixbuf pixbuf2;
try
{
pixbuf1 = new Pixbuf(filename);
pixbuf2 = pixbuf1;
}
catch (GException exception1)
{
Console.WriteLine(exception1.GetType());
Console.WriteLine("Cannot Open file.");
Environment.Exit(1);
pixbuf2 = null;
}
return pixbuf2;
}
No such probems are in evidence here.
For completeness, here is the main function.
public static void Main(string[] args)
{
if (args.Length <= 0)
{
Console.WriteLine("\nUSAGE: ImageViewer.exe \n");
return;
}
string text1 = args[0];
Application.Init();
ImageViewer.window = new Window("File Viewer");
ImageViewer.window.SetDefaultSize(200, 200);
ImageViewer.window.add_DeleteEvent(new EventHandler(ImageViewer.Window_Delete));
ScrolledWindow window1 = new ScrolledWindow(new Adjustment(IntPtr.Zero), new Adjustment(IntPtr.Zero));
VBox box1 = new VBox(false, 2);
VBox box2 = new VBox(false, 0);
MenuBar bar1 = new MenuBar();
Menu menu1 = new Menu();
MenuItem item1 = new ImageMenuItem("gtk-close", new AccelGroup(IntPtr.Zero));
MenuItem item2 = new ImageMenuItem("gtk-open", new AccelGroup(IntPtr.Zero));
item1.add_Activated(new EventHandler(ImageViewer.Window_Delete));
item2.add_Activated(new EventHandler(ImageViewer.Window_Open));
menu1.Append(item2);
menu1.Append(new SeparatorMenuItem());
menu1.Append(item1);
MenuItem item3 = new MenuItem("_File");
item3.set_Submenu(menu1);
bar1.Append(item3);
box2.PackStart(bar1, false, false, 0);
Toolbar toolbar1 = new Toolbar();
toolbar1.InsertStock("gtk-open", "Open", string.Empty, new SignalFunc(null, Window_Open), IntPtr.Zero, 0);
toolbar1.InsertStock("gtk-close", "Close", string.Empty, new SignalFunc(null, Window_Delete), IntPtr.Zero, 1);
box2.PackStart(toolbar1, false, false, 0);
box1.PackStart(box2, false, false, 0);
Pixbuf pixbuf1 = ImageViewer.GetPixbufFromFile(text1);
ImageViewer.image = new Image(pixbuf1);
ImageViewer.Refresh(text1, pixbuf1);
window1.AddWithViewport(ImageViewer.image);
box1.PackStart(window1, true, true, 0);
window1.SetPolicy(1, 1);
ImageViewer.window.Add(box1);
ImageViewer.window.ShowAll();
Application.Run();
}
Conclusion
Although Reflection is not designed to be a decompiler, it performs better than the other two decompilers tested.
--
MikeVanEmmerik - 20 Aug 2004
CategoryDecompilation