What allows a method to be intercepted in C#?

Asked

Viewed 339 times

10

Interception of a method is a technique that can be used to execute a code snippet before executing a main 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 usually when the interception technique is used the method A has no knowledge of the method B. In fact the method A may eventually be used to intercept any existing method of one or more classes.

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

I’ve used libraries like Castle Windsor that facilitate the use of subcontractors. But what I want to ask here is: How do they work? In other words, how is it possible for them to call function A before B if it does not know B. An example of how a basic developer could be done without resorting to any library would be welcome.

  • Hello. You can also use the MEF (Microsoft Extensibility Framework) that is native to . NET, and just like Castle Windsor will allow you to do the Dependency Injection, decoupling so The Caller of the libraries and functions that will be called. Please check: http://www.devmedia.com.br/extensibilidade-com-mef/19151

  • 1

    Please take a look at the Aeronaught’s reply: http://stackoverflow.com/questions/2592787/what-really-interceptors-do-with-my-sharp-class. Another article about: http://www.progware.org/blog/post/interception-and-interceptors-in-c-c- (Aspect-oriented-Programming). aspx Obs. I am copying the links because it is a lot of content to be translating and I have no way to replicate the illustrations of the second link.

1 answer

13


Do you mention the Castle Windsor, which is for injection of dependency, but the content of your question is even related to the Castle Dynamicproxy, which as the name suggests is for the creation of dynamic proxies.

The code you wrote also could not be called "interception" or even "simplified", since the consumer is consuming directly To and doesn’t even know that B will be invoked.

Interception would be the consuming invoke B and the code of To be invoked in a transparent manner, without B has been programmed for this and without the consumer himself knowing it.

How dynamic proxy works (Dynamic proxy)

Basically, the Castle Dynamicproxy creates a class that inherits of the class for which it will serve as a proxy and override the members of this class.

The consumer of the original class does not create an instance of it directly; instead he asks Castle for the instance, and Castle delivers an instance of the inherited class he created automatically, more or less like this (pseudo code):

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

Then the variable object contains a non Classea but something like "Classea$Proxy12349876", which is the inheritance of Classea automatically created by Castle.

Now, for each method invoked in object, the instance of "Classea$Proxy12349876" will attempt to invoke, before and after, the code you wrote in the Classeinterceptadora.

Important observe that as Castle will create a inheritance of its class, it will only be possible to replace the virtual hers.

Dynamic proxy utility (an example)

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

One entity can refer to 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 recover an employee from the database, Nhibernate will not give you an instance of Official, but rather an instance of a class he created inheriting from Official. This heritage that Nhibernate creates using Castle will act as a proxy for the class Official.

So, if the loading of the related entity is configured as Lazy load, when you do that:

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

staff will contain a proxy, which will also deliver a proxy in functionary.. Then, the existing proxy instance in functionary. It will contain only the ID in memory, and will deliver it to you without having to search the department’s database for any information. Now, if you do this:

string nomeDepartamento = funcionario.departamento.nome;

then the existing proxy instance in functionary. will make a query in the database, seeking all department information to make it available to you.

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

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

The proxy created by Castle to intercept functionary. in the above example is a Pattern design.

This Pattern design can be easily implemented in C# without having to resort to any external library. 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 does especially, and that C# has nothing native to do in such a complete and simplified way, is to create the proxy dynamically without the class intercepted by the proxy and neither the consumer need be aware that there is a proxy there (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 will be intercepted by the proxy are virtual.

  • I believe that using the CodeDOM to create proxys dynamically is an interesting alternative :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.