Use reflection to get assembly type and method sizes for comparison


I wanted to know what changed between two versions of a managed assembly. Software changes over time, and seeing what changed can be important in understanding behavior.
So I wrote a little program to show the assembly contents, sorted by size, showing the size of various components such as classes and methods.

Because it doesn’t look at things like static members, manifests, etc.  It’s not complete, and left as an exercise to the reader.

Note how it calculates each node’s cost by summing it’s children, then uses the size as a sort description.


<code>

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.Diagnostics;
 
// Start Visual Studio, File->New->Project->C#, WPF Application. call it "MgdCodeSize"
// Replace MainWindow.xaml.cs wtih this content
 
namespace MgdCodeSize
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		public MainWindow()
		{
			InitializeComponent();
			this.Loaded += MainWindow_Loaded;
			this.WindowState = WindowState.Maximized;
		}
 
		public class MyTreeViewItem : TreeViewItem
		{
			public int size { getset; }
			string _name;
			public MyTreeViewItem(string name)
			{
				this._name = name;
			}
			public void CalcHeader(bool expand = true)
			{
				foreach (MyTreeViewItem child in this.Items)
				{
					this.size += child.size;
				}
				var sp = new StackPanel()
				{
					Orientation = Orientation.Horizontal
				};
				sp.Children.Add(new TextBox()
				{
					Text = size.ToString()
				});
				sp.Children.Add(new TextBox()
				{
					Text = _name
				});
				this.Header = sp;
				this.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("size", System.ComponentModel.ListSortDirection.Descending));
				if (expand)
				{
					this.IsExpanded = true;
				}
			}
			public override string ToString()
			{
				return $"{this.size} {this._name}";
			}
		}
		private void MainWindow_Loaded(object sender, RoutedEventArgs e)
		{
			try
			{
				var filename = @"C:\Program Files (x86)\Microsoft Visual Studio\Preview\Enterprise\Common7\IDE\EntityFramework.dll";
				var asm = Assembly.LoadFrom(filename);
				var tv = new TreeView();
				this.Content = tv;
				var tvFileNode = new MyTreeViewItem(filename);
				tv.Items.Add(tvFileNode);
				foreach (var module in asm.Modules)
				{
					var tvModuleNode = new MyTreeViewItem(module.Name);
					tvFileNode.Items.Add(tvModuleNode);
 
					foreach (var type in module.GetTypes())
					{
						var tvTypeNode = new MyTreeViewItem(type.Name);
						tvModuleNode.Items.Add(tvTypeNode);
						var methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
						foreach (var method in methods)
						{
							var methodBody = method.GetMethodBody();
							var bytes = methodBody?.GetILAsByteArray();
							var tvMethodNode = new MyTreeViewItem(method.Name);
							if (bytes != null)
							{
								var numbytes = bytes.Length;
								tvMethodNode.size = numbytes;
								tvTypeNode.Items.Add(tvMethodNode);
							}
							tvMethodNode.CalcHeader(expand: false);
						}
						tvTypeNode.CalcHeader(expand: false);
					}
					tvModuleNode.CalcHeader();
				}
				tvFileNode.CalcHeader();
 
			}
			catch (Exception ex)
			{
				this.Content = ex.ToString();
			}
		}
	}
}

</code>

Comments (0)

Skip to main content