What is it that allows a method to be intercepted in C #?

10

Intercepting a method is a technique that can be used to execute a code snippet before executing a master action. That is, in a very simplified way this would also be an example of interception:

public void A(){ 
    Console.Writeline("Estou a interceptar B!");
    B(); 
}
private void B(){
    Console.Writeline("Eu sou a acção principal B");
}

The difference is that normally, when the intercept technique is used method A is not aware of method B. In fact method A can be eventually used to intercept any existing method of one or more classes. >

This technique can be used for example to log in the method, logging in the name information and parameters of the method that will be called.

I've used libraries like Castle Windsor that make it easy to use interceptors. But what I want to ask here is: How do they work? In other words, how can you call function A before B if it does not know B. An example of how a basic interceptor could being done, without resorting to any library would be welcome.

    
asked by anonymous 08.02.2017 / 19:55

1 answer

13

You mention the Castle Windsor , which is for dependency injection, but the content of your question is even related the Castle DynamicProxy , which as the name suggests is for creating dynamic proxies . p>

The code you wrote also could not be called "intercept" or even "simplified", since the consumer is consuming directly A and strictly not even know that B will be invoked.

Interception would be to invoke B and the A code be invoked transparently, without B being programmed for this without the consumer being aware of it.

How Dynamic Proxy Works

In essence, Castle DynamicProxy creates a class that inherits from the class it will serve as a proxy for and overrides the members of this class.

The consumer of the original class does not instantiate it directly; instead it requests the instance from Castle, and Castle delivers an instance of the inherited class that it created automatically, more or less like this (pseudo code):

ClasseA objeto = Castle.CrieInstancia<ClasseA>(ClasseInterceptadora);

Then the object contains an instance not of ClassA but rather of something type "classA $ Proxy12349876" , which is the inheritance of ClassA created automatically by Castle.

Now, for each method invoked in object , the instance of "ClassA $ Proxy12349876" will try to invoke before and after the code you typed in < in> Interceptor Class .

Important Note that since Castle will create a inheritance from your class, you can only replace the virtual members with it.

>

Utility of a dynamic proxy (an example)

When you use NHibernate , you declare entities (roughly speaking, classes that will represent database records).

An entity can reference another, more or less like this (pseudo code):

class Funcionario {
    long id;
    string nome;
    Departamento departamento;
}

class Departamento {
    long id;
    string nome;
    string centroDeCusto;
}

When you retrieve an employee from the database, NHibernate will not give you an Employee instance, but rather an instance of a class it created inheriting from Employee >. This inheritance that NHibernate creates using Castle will act as a proxy for the Employee class.

So if the related entity load is set to lazy load , when you do this:

Funcionario funcionario = db.getFuncionarioDoMes();
long idDepartamento = funcionario.departamento.id;

official will contain a proxy, which will also deliver a proxy in official.departamento . Then the existing proxy instance in official.departamento will only contain the id in memory, and will deliver you without having to search the database for all the information in the department. Now, if you do this:

string nomeDepartamento = funcionario.departamento.nome;

then the existing proxy instance in official.de will query the database, searching for all information in the department to make it available to you.

In this example, it was interesting to use a proxy so you do not need to encode all this technological complexity in your entity.

How to make a proxy (an "interceptor") without resorting to a library

The proxy created by Castle to intercept the consumption of official.departamento in the above example is a design pattern .

This design pattern can be easily implemented in C # without having to resort to any external libraries. See this example from Wikipedia :

interface ICar
{
    void DriveCar();
}

// Real Object
public class Car : ICar
{
    public void DriveCar()
    {
        Console.WriteLine("O carro foi dirigido!");
    }
}

//Proxy Object
public class ProxyCar : ICar
{
    private Driver driver;
    private ICar realCar;

    public ProxyCar(Driver driver)
    {
        this.driver = driver;
        this.realCar = new Car();
    }

    public void DriveCar()
    {
        if (driver.Age < 18)
            Console.WriteLine("Desculpe, o motorista é muito jovem para dirigir.");
        else
            this.realCar.DriveCar();
     }
}

public class Driver
{
    private int Age { get; set; }

    public Driver(int age)
    {
        this.Age = age;
    }
}

// Como usar o proxy
private void btnProxy_Click(object sender, EventArgs e)
{
    ICar car = new ProxyCar(new Driver(16));
    car.DriveCar();

    car = new ProxyCar(new Driver(25));
    car.DriveCar();
}

And there are several other ways to implement a proxy.

What Castle is special about, and this C # has nothing native to do so completely and simplified, is to create the dynamically proxy without the class intercepted by the proxy and neither (there is no need for the intercepted class to implement a certain interface, for example, and it is not necessary to write a unique proxy for each class that will be intercepted).

The only thing you need to do based on Castle's proxy is to ensure that the methods that are going to be intercepted by the proxy are virtual.

    
15.02.2017 / 18:35