Assembly.GetExecutingAssembly()

System.Reflection – Working with the Assembly Class

Posted on Updated on

The objects within the System.Reflection namespace of the .NET Framework provide us a means to get assembly and type information at runtime. Reflection is useful in situations where you need to introspect assemblies and their types, either to gain information or to make use of their functionality dynamically without knowing its specifics in advance. Sounds pretty cool, right? Well it is!

This article will walk you through the basics of Reflection and the Assembly class and will be followed by additional articles that dive much more deeply into the objects within the System.Reflection namespace.

The System.Reflection.Assembly Class

The Assembly class is the primary class within the System.Reflection namespace. This will be our starting point as we take a look at Reflection.

First, we will create a simple Visual Studio solution that we will call ‘ReflectionWalkthroughSolution’.

In this solution, we will add a C# Class Library project which we will call ‘MyClassLibrary’.

Next, we will add a Console Application which we will call ‘MyConsoleApplication’. These names are nonsensical, but this solution is merely for demonstration purposes :).

So, after doing these things, our Solution Explorer should look like this:

.NET Reflection - Solution Explorer Getting Started

MyConsoleApplication is bolded because I have set it as the startup project. This will allow us to hit F5 to debug the app and be able to use the console application as our entry point.

Next, expand MyConsoleApplication and Add a Reference to the MyClassLibrary project. Once this is done we are ready to start writing a little code.

Assembly.GetExecutingAssembly() Method

The first thing we will look at is how to get a reference to the assembly that is currently executing. To do this we will add some simple code in the Main() method of our console application as shown below. After writing this code, place a breakpoint on the line, then hover the thisAssembly object and take a look at the properties of the assembly and their values.

static void Main(string[] args)
{
    //get the currently executing assembly
    Assembly thisAssembly = Assembly.GetExecutingAssembly();

}

With the code running, when the breakpoint is hit, we can right-click and Add a Watch to the thisAssembly object. When we hit F10 to step over the line, the Watch window is populated with information pertaining to the ‘thisAssembly’ object. See the illustration below.

Hint: Click the image to view it full-size.

.NET Reflection - Assembly.GetExecutingAssembly() Watch Window
Properties of the ‘thisAssembly’ Assembly object

 

Let’s discuss some of the properties that are shown in the Watch window above.

The CodeBase property returns the full path at which the assembly resides. In other words, the execution location for the assembly, including the name of the assembly.dll file itself.

The CustomAttributes property is an IEnumerable<CustomAttributeData> type that displays all of the custom attributes that exist at the assembly level. If you take a look you will see that many of these come directly from the AssemblyInfo.cs file that is found under the Properties folder of the project.

Assembly.CustomAttributes Illustration
The Assembly.CustomAttributes property expanded.

We will dive into custom attributes in a later post. Attributes can be applied to assemblies, classes, properties, methods, and more and through Reflection can be retrieved and read using the appropriate objects. These attributes exist at the assembly level. For now, just be aware that these attributes can be retrieved in this way.

The DefinedTypes property is an IEnumerable<TypeInfo> type that displays all of the types (classes) defined within the assembly. In our simple little console application we only have one defined type. See below.

The Assembly.DefinedTypes property expanded
The Assembly.DefinedTypes property expanded

Looking ahead to later posts, once you have a reference to an Assembly, knowing the types defined in the assembly allow you to dive into the assembly and then into each type as needed.

The FullName property is a string value that displays the full name of the assembly. This is important when discussing a topic such as strong naming.

The Assembly.FullName property
The Assembly.FullName property

There are other properties of the Assembly object that are noteworthy for this introduction. They are the GlobalAssemblyCache property which tells you whether or not the assembly is GAC’ed, the ImageRuntimeVersion which tells you the full version of the .NET Framework against which the assembly is compiled, and the MainfestModule which gives specific information about the assembly itself.

Getting Assemblies loaded in the Current AppDomain (AppDomain.Current.GetAssemblies() Method)

Now that we’ve taken a quick look at the properties of an Assembly and how to get a reference to the currently executing assembly, let’s branch out a little and retrieve all of the assemblies referenced and loaded into the current AppDomain. An AppDomain is an isolated environment in which an application executes. The AppDomain class belongs to the System namespace. To retrieve the AppDomain for the currently executing application, we will the AppDomain.Current property.

If we return to the Main() method of the Program class of our little console application and remove the code we wrote originally and replace it with this code:

static void Main(string[] args)
{
    Assembly thisAssembly = Assembly.GetExecutingAssembly();

    //Get assemblies loaded in the current AppDomain
    Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();

    //create a StringBuilder to hold assembly information
    StringBuilder sb = new StringBuilder();

    //iterate through the array and write info for each assembly
    foreach (Assembly assembly in assemblies)
    {
        //let's create some rudimentary formatted output to show property values
        //for each assembly
        sb.AppendLine("================================================================");
        sb.AppendLine(String.Format("Assembly: {0}", assembly.FullName));
        sb.AppendLine("================================================================");

        sb.AppendLine(String.Format("CodeBase: {0}", assembly.CodeBase));
        sb.AppendLine(String.Format("Location: {0}", assembly.Location));
        sb.AppendLine(String.Format("Number of Types: {0}", assembly.DefinedTypes.Count().ToString()));
        sb.AppendLine(String.Format("Number of Custom Attributes:  {0}", assembly.CustomAttributes.Count().ToString()));
        sb.AppendLine(String.Format(".NET Runtime Version: {0}", assembly.ImageRuntimeVersion));

        //you can add more stuff here to see more properties...
    }

    string output = sb.ToString();
}

When we view the formatted output from our StringBuilder, it should look something like this:

================================================================
Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
Location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll
Number of Types: 3029
Number of Custom Attributes:  36
.NET Runtime Version: v4.0.30319
================================================================
Assembly: Microsoft.VisualStudio.HostingProcess.Utilities, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
================================================================
CodeBase: file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.HostingProcess.Utilities/11.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.HostingProcess.Utilities.dll
Location: C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities\11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.dll
Number of Types: 12
Number of Custom Attributes:  17
.NET Runtime Version: v2.0.50727
================================================================
Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
Number of Types: 2273
Number of Custom Attributes:  27
.NET Runtime Version: v4.0.30319
================================================================
Assembly: System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Drawing\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll
Number of Types: 303
Number of Custom Attributes:  25
.NET Runtime Version: v4.0.30319
================================================================
Assembly: System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
Number of Types: 2278
Number of Custom Attributes:  29
.NET Runtime Version: v4.0.30319
================================================================
Assembly: Microsoft.VisualStudio.HostingProcess.Utilities.Sync, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
================================================================
CodeBase: file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.HostingProcess.Utilities.Sync/11.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll
Location: C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities.Sync\11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.Sync.dll
Number of Types: 5
Number of Custom Attributes:  18
.NET Runtime Version: v2.0.50727
================================================================
Assembly: Microsoft.VisualStudio.Debugger.Runtime, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
================================================================
CodeBase: file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.Debugger.Runtime/11.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.Debugger.Runtime.dll
Location: C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\11.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll
Number of Types: 10
Number of Custom Attributes:  17
.NET Runtime Version: v2.0.50727
================================================================
Assembly: vshost32, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
================================================================
CodeBase: file:///C:/Temp/ReflectionWalkthroughSolution/MyConsoleApplication/bin/Debug/MyConsoleApplication.vshost.exe
Location: C:\Temp\ReflectionWalkthroughSolution\MyConsoleApplication\bin\Debug\MyConsoleApplication.vshost.exe
Number of Types: 1
Number of Custom Attributes:  19
.NET Runtime Version: v4.0.30319
================================================================
Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll
Number of Types: 929
Number of Custom Attributes:  25
.NET Runtime Version: v4.0.30319
================================================================
Assembly: System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml.Linq/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.Linq.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll
Number of Types: 86
Number of Custom Attributes:  22
.NET Runtime Version: v4.0.30319
================================================================
Assembly: System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Data.DataSetExtensions/v4.0_4.0.0.0__b77a5c561934e089/System.Data.DataSetExtensions.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Data.DataSetExtensions\v4.0_4.0.0.0__b77a5c561934e089\System.Data.DataSetExtensions.dll
Number of Types: 25
Number of Custom Attributes:  24
.NET Runtime Version: v4.0.30319
================================================================
Assembly: Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/Microsoft.CSharp/v4.0_4.0.0.0__b03f5f7f11d50a3a/Microsoft.CSharp.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.CSharp\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.CSharp.dll
Number of Types: 316
Number of Custom Attributes:  23
.NET Runtime Version: v4.0.30319
================================================================
Assembly: System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.Data/v4.0_4.0.0.0__b77a5c561934e089/System.Data.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_32\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll
Number of Types: 1049
Number of Custom Attributes:  21
.NET Runtime Version: v4.0.30319
================================================================
Assembly: System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================================
CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
Location: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll
Number of Types: 1229
Number of Custom Attributes:  25
.NET Runtime Version: v4.0.30319
================================================================
Assembly: MyConsoleApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
================================================================
CodeBase: file:///C:/Temp/ReflectionWalkthroughSolution/MyConsoleApplication/bin/Debug/MyConsoleApplication.EXE
Location: C:\Temp\ReflectionWalkthroughSolution\MyConsoleApplication\bin\Debug\MyConsoleApplication.exe
Number of Types: 1
Number of Custom Attributes:  14
.NET Runtime Version: v4.0.30319

Pretty simple, right? Now let’s dig into the Assembly a little deeper.

Getting Types within an Assembly (Assembly.GetTypes() Method)

Every Assembly can contain one of more Types. We can retrieve all of these types via the Assembly.GetTypes() method. To try this out, we replace the code in our console application’s Program class’s Main() method with this code:

static void Main(string[] args)
{
    Assembly thisAssembly = Assembly.GetExecutingAssembly();

    //get all of the Types defined in this Assembly
    Type[] types = thisAssembly.GetTypes();

    //robust code always checks for null FIRST
    if (types != null && types.Length > 0)
    {
        //we'll create a StringBuilder for our formatted output
        StringBuilder sb = new StringBuilder();

        //iterate through the Type[] array
        foreach (Type type in types)
        {
            sb.AppendLine("===============================================================");
            sb.AppendLine(String.Format("Type Name: {0}", type.Name));
            sb.AppendLine("===============================================================");

            sb.AppendLine(String.Format("Type FullName: {0}", type.FullName));
            sb.AppendLine(String.Format("Namespace: {0}", type.Namespace));

            sb.AppendLine(String.Format("Is it a Class?: {0}", type.IsClass.ToString()));
            sb.AppendLine(String.Format("Is it an Interface?: {0}", type.IsInterface.ToString()));
            sb.AppendLine(String.Format("Is it Generic?: {0}", type.IsGenericType.ToString()));
            sb.AppendLine(String.Format("Is it Public?: {0}", type.IsPublic.ToString()));
            sb.AppendLine(String.Format("Is it Sealed?: {0}", type.IsSealed.ToString()));

            sb.AppendLine(String.Format("Qualified Name: {0}", type.AssemblyQualifiedName));

            if (type.BaseType != null && !String.IsNullOrEmpty(type.BaseType.Name))
            {
                sb.AppendLine(String.Format("Base Type: {0}", type.BaseType.Name));
            }

            //there are many, many more properties that an be shown...
        }

        string output = sb.ToString();
    }
}

In our console application, there is only one type, the Program class. When we execute the code above we see information for that single type.

===============================================================
Type Name: Program
===============================================================
Type FullName: MyConsoleApplication.Program
Namespace: MyConsoleApplication
Is it a Class?: True
Is it an Interface?: False
Is it Generic?: False
Is it Public?: False
Is it Sealed?: False
Qualified Name: MyConsoleApplication.Program, MyConsoleApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Base Type: Object

Now that we’ve moved down a level and looked at Types within an assembly, let’s move down one more level.

The next post discusses the System.Reflection.Type class and its properties and methods.