Dynamically Loading Assemblies


The act of loading external assemblies on demand is known as a dynamic loading.

System.Reflection defines a class named Assembly. Using this class, you can dynamically lead an assembly, as well as discover properties about the assembly itself. In essence, the Assembly class provides methods that allow you to programmatically load assemblies off disk.

string asmName = Console.ReadLine();
Assembly asm = null;
try
 {
     asm = Assembly.LoadFrom(asmName);
     DisplayTypesInAsm(asm);
 }
catch (Exception)
 {
     Console.WriteLine("No assembly");
 }
 
static void DisplayTypesInAsm(Assembly asm)
 {
     Console.WriteLine(asm.FullName);
     Type[] types = asm.GetTypes();
     foreach(Type t in types)
     {
         Console.WriteLine(t);
     }
 }

Reflecting on Framework Assemblies


The Assembly.Load() method has several overloads.

// Load Version 1.0.0.1 of CarLibrary using the default Culture.
Assembly a = Assembly.Load("CarLibrary, Version=1.0.01, PublickeyToken=null, Culture\"\"");

The System.Reflection namespace supplies the AssemblyName type, which allows you to represent the preceding string information is a handy object variable. Typically, this class is used in conjunction with System.Version, which is a wrapper around an assembly's version number.

AssemblyName asmName;
asmName = new AssemblyName();
asmName.Name = "CarLibrary";
Version v = new Version("1.0.0.1");
asmName.Version = v;
Assembly a = Assembly.Load(asmName);

To load a .NET Framework assembly (not .NET), the Assembly.Load() parameter should specify a PublicKeyToken value.

var displayName = "Microsoft.EntityFrameworkCore, Version=6.0.0.0, Culture=neutral, PublicKeyToken=01231...";
Assembly asm = Assembly.Load(displayName);

Understanding Late Binding

Late binding is a technique in which you can create an instance of a given type and invoke its members at runtime without having hard-coded compile-time knowledge of its experience.

The System.Activator Class

This class is the key to the .NET late-binding process. You are interested in only in the Activator.CreateInstance() method, which is used to create an instance of a type through late binding. This method returns a System.Object.

// This program will load an external library and create an object using late binding.
Assembly a = null;
try
 {
     a = Assembly.LoadFrom("CarLibrary");
 }
catch (Exception ex)
 {
     Console.WriteLine(ex.Message);
 }
if (a != null)
 {
     CreateUsingLateBinding(a);
 }
 
private static void CreateUsingLateBinding(Assembly asm)
 {
     try
     {
         // GetMetadata for the Minivan type
         Type miniVan = asm.GetType("CarLibrary.Minivan");
         // Create a Minican intsance on the fly.
         object obj = Activator.CreateInstance(miniVan);
         Console.WriteLine(obj);
     }
     catch (Exception)
     {
    throw;
     }
 }

You will need to manually place a copy of CarLibrary.dll into the project file folder.

Note: Don't add a reference to CarLibrary.dll for this example. The whole point of late binding is that you are trying to create an object that is now known at compile time.

Invoking Methods with No Parameters

The first step is to obtain a MethodInfo object for the MyMethod() method using Type.GetMethod().

Then you use Invoke() calling the method.

static void CreateUsingLateBinding(Assembly asm)
 {
     try
     {
         Type miniVan = asm.GetType("CarLibrary.Minivan");
         object obj = Activator.CreateInstance(miniVan);
         // Get info for TurboBoost
         MethodInfo mi = miniVan.GetMethod("TurboBoost");
         // Invoke method ('null' for no parameters).
         mi.Invoke(obj, null);
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
     }
 }

Invoking Methods with Parameters

When you want to use late binding to invoke a method requiring parameters, you should package up the arguments as a loosely typed array of objects.

public void TurnOnRadio(bool musicOn, MusicMediaEnum mm)
 {
     System.Windows.Forms.MessageBox.Show(musicOn ? $"Jamming {mm}" : "Quiet Time");
 }
public enum MusicMediaEnum
 {
     musicCd,
     musicRadio
 }
 
static void InvokeMethodWithArgsUsingLatebinding(Assembly asm)
 {
     try
     {
         Type s = asm.GetType("CarLibrary.SportsCar");
         object obj = Activator.CreateInstance(s);
         MethodInfo mi = s.GetMethod("TurnOnRadio");
         mi.Invoke(obj, new object[] { true, 2 });
     }
     catch (Exception)
     {
         Console.WriteLine("Message");
     }
 }

Understanding the Role of .NET Attributes

The .NET platform provides a way for programmers to embed additional metadata into an assembly attributes. In a nutshell, attributes are nothing more than code annotations that can applied to a given type (class,interface,structure etc.), member (property,method,etc.), assembly, or module..

.NET attributes are class types that extend the abstract System.Attribute base class.

  1. [CLSCompliant] : Enforces the annotated item to conform to the rules of CLR.
  2. [DllImport] : Allows .NET Code to make calls to any unmanaged C- or C++ based code library, including the API of the underlying operating system.
  3. [Obsolete] : Marks a deprecated type or member.

Applying Attributes in C#

Assume you want to build a class named Motorcycle that can be persisted to JSON format. If you have a field that should not be exported to JSON, you can apply [JsonIgnore].

public class Motorcycle
 {
     [JsonIgnore]
     public float weightOfCurrentPassengers;
     // These fields are still Serializable
     public bool hasRadioSystem;
     public bool hasHeadSet;
 }

You have a legacy C# class type (HorseAndBuggy) that was attributed to have a custom XML namespace.

[XmlRoot(Namespace ="https://dotnetguard.blog"),Obsolete("Use another vehicle")]

OR

[XmlRoot(Namespace = "https://dotnetguard.blog")]
[Obsolete("Use another vehicle")]

C# Attribute Shorthand Notation

As a naming convention, all .NET attributes are suffixed with the Attribute token. However, to simplify the process of applying attributes, the C# language does not require you to type in the Attribute syntax.

[XmlRootAttribute(Namespace ="https://dotnetguard.blog")]
 [ObsoleteAttribute("Use another vehicle")]

  1. Attributes are classes that are derive from System.Attribute.
  2. Attributes are applied in C# using square brackets.