Injeção de Dependência em C#: um guia simples para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

O que é Dependency Injection (DI) em C# e por que é necessário?

\n\n

Dependency Injection (injeção de dependências) é um padrão de projeto que torna o código mais flexível, testável e sustentável. Em vez de a classe criar os objetos dos quais depende, esses objetos são "injetados" externamente. Este é um dos princípios-chave que fundamentam o desenvolvimento moderno em C# e .NET.

\n\n

Imagine que você está escrevendo um aplicativo para enviar notificações por e-mail. Se sua classe NotificationService criar diretamente uma instância de SmtpClient, ao trocar o servidor de e-mail ou precisar usar outro método de envio (por exemplo, via API), você terá que reescrever o código. A DI resolve esse problema.

\n\n

O problema sem Dependency Injection

\n\n

Vamos considerar um exemplo típico de código ruim, onde a dependência é criada dentro da classe:

\n\n
public class EmailService\n{\n    private SmtpClient _smtpClient;\n\n    public EmailService()\n    {\n        // Acoplamento rígido a uma implementação específica\n        _smtpClient = new SmtpClient("smtp.gmail.com", 587);\n    }\n\n    public void SendEmail(string to, string subject, string body)\n    {\n        // Lógica de envio\n    }\n}\n\npublic class NotificationService\n{\n    private EmailService _emailService;\n\n    public NotificationService()\n    {\n        _emailService = new EmailService(); // Acoplamento rígido\n    }\n\n    public void NotifyUser(string email)\n    {\n        _emailService.SendEmail(email, "Notificação", "Olá!");\n    }\n}
\n\n

Desvantagens dessa abordagem:

\n
    \n
  • Alto acoplamento (tight coupling): As classes NotificationService e EmailService estão rigidamente ligadas entre si.
  • \n
  • Dificuldade de teste: É impossível substituir EmailService por um objeto mock durante os testes unitários.
  • \n
  • Dificuldade de extensão: Se for necessário adicionar notificações por SMS, será preciso alterar a lógica dentro de NotificationService.
  • \n
\n\n

Implementação de Dependency Injection em C#

\n\n

A DI resolve esses problemas usando três abordagens principais: injeção via construtor, via propriedade e via método. A mais comum e recomendada é a injeção via construtor (Constructor Injection).

\n\n

Passo 1. Criando a interface

\n

Primeiro, definimos uma abstração (interface) que descreve o contrato para envio de mensagens:

\n\n
public interface IMessageSender\n{\n    void Send(string to, string message);\n}
\n\n

Passo 2. Implementando serviços concretos

\n

Agora, criamos algumas implementações dessa interface:

\n\n
public class EmailSender : IMessageSender\n{\n    public void Send(string to, string message)\n    {\n        Console.WriteLine($"Enviando e-mail para {to}: {message}");\n    }\n}\n\npublic class SmsSender : IMessageSender\n{\n    public void Send(string to, string message)\n    {\n        Console.WriteLine($"Enviando SMS para {to}: {message}");\n    }\n}
\n\n

Passo 3. Aplicando DI via construtor

\n

Agora, a classe NotificationService não cria as dependências por conta própria, mas as recebe através do construtor:

\n\n
public class NotificationService\n{\n    private readonly IMessageSender _messageSender;\n\n    // Injeção de dependência via construtor\n    public NotificationService(IMessageSender messageSender)\n    {\n        _messageSender = messageSender;\n    }\n\n    public void Notify(string userContact, string message)\n    {\n        _messageSender.Send(userContact, message);\n    }\n}
\n\n

Agora podemos trocar facilmente as implementações:

\n\n
// Usando Email\nvar emailSender = new EmailSender();\nvar emailNotifier = new NotificationService(emailSender);\nemailNotifier.Notify("user@example.com", "Olá via e-mail!");\n\n// Usando SMS\nvar sms                

Blogs

Book Recommendations