Late binding. Method call. Example. Class System.Activator. Method Invoke()

Late binding. Method call. Example. Class System.Activator. Method Invoke()


Contents


1. What is the essence of late binding?

Late binding is the technology of creating and calling an instance of some type (for example, a class) during the execution of a program without its previous connection at the compilation stage.

Late binding allows you to programmatically use an instance of the type of some assembly, information about which is not hardcoded at the compilation stage. Information about an assembly is obtained “on the fly”.

2. What tools are provided in C# .NET for the implementation of late binding? Class System.Activator. Method Invoke()

To implement late binding, the System.Activator class features are used. An instance (object) of a type (for example, a class) that is formed “on the fly” is created using the overloaded method Activator.CreateInstance().

Methods placed in this type (class) can be obtained using the MethodInfo class. For more information about obtaining information about the methods of assembly with the help of reflection can be found in the topic:

To call the method received on the fly, the Invoke() method of the MethodInfo class is used.

3. What is the main namespace you need to connect in the program to implement late binding?

To use the late binding features, you must include the System.Reflection namespace.

4. An example that demonstrates late binding for calling methods from another assembly

Let the assembly, which is located in the ClassLibrary1.dll file, be given. This assembly is formed in Microsoft Visual Studio 2017 using the “Class Library (.NET Framework)” template.

The assembly contains one class named Area. This class contains methods that define:

  • the AreaTriangle() method, which calculates the area of a triangle using its sides a, b, c;
  • the AreaCircle() method, which calculates the area of a circle of a given radius r.

The program code for the ClassLibrary1.dll assembly is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

// the namespace MathLibrary
namespace MathLibrary
{
  // Area class - contains methods for determining the area of various geometric shapes
  public class Area
  {
    // method that determines the area of a triangle on its sides
    public double AreaTriangle(double a, double b, double c)
    {
      // checking whether a, b, c are set correctly
      if (((a + b) > c) || ((a + c) > b) || ((b + c) > a))
        return -1;

      double p;
      double s;
      p = (a + b + c) / 2; // semiperimeter

      // Heron's formula
      s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));
      return s;
    }

    // method that determines the area of a circle by its radius
    public double AreaCircle(double r)
    {
      return 3.1415 * r * r;
    }
  }
}

The following is the text of an application of the Console Application type, which uses late binding to perform the following operations on the assembly ClassLibrary1.dll:

  • loads the assembly ClassLibrary1.dll. Previously the ClassLibrary1.dll assemly file can be saved in the folder with this application. This is done using a file manager (for example Total Commander);
  • invokes the AreaTriangle() method from the Area class of the assembly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

// include the namespace to implement late binding
using System.IO;
using System.Reflection;

namespace ConsoleApp3
{
  class Program
  {
    static void Main(string[] args)
    {
      // implementation of late binding using the assembly ClassLibrary1.dll
      Assembly asm = null; // declare a variable of type 'assembly'

      // 1. Get access to the assembly
      try
      {
        // attempt to obtain information about the assembly
        asm = Assembly.Load("ClassLibrary1");

        // check if everything is OK
        if (asm == null) return;
      }
      catch (FileNotFoundException ex)
      {
        // if the attempt is unsuccessful, an error message is occured.
        Console.WriteLine(ex.Message);
        return;
      }

      // 2. Get the instance of ComplexOperations type from ClassLibrary1.dll asembly
      Type tp;
      try
      {
        // attempt to get complexOperations type metadata
        tp = asm.GetType("MathLibrary.Area");

        // create an instance of the ComplexOperations class
        // using late binding
        object ob = Activator.CreateInstance(tp);

        // 3. Invoke the AreaTriangle() methods from Area class
        // 3.1. Get the method's instance
        MethodInfo mi;
        mi = tp.GetMethod("AreaTriangle"); // get the instance of AreaTriangle() method

        // 3.2. Form the method's parameters
        double a = 5, b = 4, c = 3;
        object[] parameters = new object[] { a, b, c };

        // 3.3. Invoke the method
        double area;
        area = (double)mi.Invoke(ob, parameters); // area = 6
        Console.WriteLine("Area = {0}", area);
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }
  }
}

Let’s explain some code snippets. To implement late binding, you must include the System.IO and System.Reflection namespaces in your project.

The first step is accessing the assembly of the ClassLibrary1.dll using the method

asm = Assembly.Load("ClassLibrary1");

In this case, the assembly file and the application file must be placed in the same directory. If you need to load an assembly from another directory, then you need to use the Assembly.LoadFrom() method, in which the parameter specify the full path to the assembly. For example, the method’s call may be as follows.

asm = Assembly.LoadFrom("C:\\ABCDEF\\ClassLibrary1.dll");

In this case, you need to specify the name of the assembly file with the extension *.dll.

In the second step, an instance of the class of the type ComplexOperations is created. First, type metadata is obtained using the string

tp = asm.GetType("MathLibrary.Area");

Here, the namespace is first defined (MathLibrary). Then the class name is specified in the assembly (Area). It is important that the class in the assembly be declared as public. Otherwise it will be unavailable.

To create an instance of the class ComplexOperations, the CreateInstance() method from the Activator class is used. The method receives as an input parameter an instance of the metadata type

In the third step, the AreaTriangle() method from the Area class is called. This is implemented using late binding.

First, an instance of mi of the MethodInfo type is created, which corresponds to the AreaTriangle() method. This instance contains information about the method. Then a list of parameters of type array object[] is created that will be passed to the method. The third step is completed by calling the Invoke() method, which corresponds to the AreaTriangle() method of the Area class.

5. What is the general algorithm for calling a given method from an assembly?

The sequence of steps is as follows:

1. Include namespace System.Reflection

using System.Reflection;

2. Get an instance of the assembly

Assembly asm = Assembly.Load("NameOfAssembly");

where NameOfAssembly – the name of the assembly whose method you want to invoke “on the fly”.

3. Get an instance of Type, which corresponds to the type metadata. This is done using the GetType() method.

Type tp = asm.GetType("NameSpace.Type");

where

  • NameSpace – the name of the namespace in which the type is declared (class, structure, interface, enumeration, delegate);
  • Type – the name of the type whose method you want to invoke.

4. Create an instance of the desired class using late binding. To do this, use the CreateInstance() method of Activator class.

object ob = Activator.CreateInstance(tp);

Here tp is a previously obtained type instance.

5. Get an instance of the mi of MethodInfo type, which corresponds to the method of the type tp. To do this, use the GetMethod method.

MethodInfo mi = tp.GetMethod("NameOfMethod");

where NameOfMethod – the name of the method to be executed using late binding.

6. Create a list of parameters of object[] type. The object[] array is obtained in the standard way using the new operator. For example

object[] parameters = new object[] { "Text parameter", true, 2, 3.85f };

In this example, 4 parameters of types string, bool, int, float are formed.

7. Call an instance mi using the Invoke() method.

mi.Invoke(ob, parameters);

If the method takes no parameters, it is passed null. For example

mi.Invoke(ob, null);

6. Is it possible to call methods of static classes using late binding?

No, it isn’t. This is due to the fact that late binding involves the creation of an instance (object) of a class. But, as you know, a static class object cannot be created.

For example. It is not possible to invoke the methods of the System.Math class using late binding, because the System.Math class is declared as static. Methods of this class will be called directly:

double x = Math.Sqrt(81); // x = 9.0


Related topics