C # как правильно утилизировать SmtpClient? - PullRequest
31 голосов
/ 06 мая 2010

VS 2010 анализ кода сообщает следующее:

Предупреждение 4 CA2000: Microsoft.Reliability: В методе «Mailer.SendMessage ()» объект «клиент» расположен не по всем путям исключений.Вызовите System.IDisposable.Dispose для объекта 'client', прежде чем все ссылки на него выйдут из области видимости.

Мой код:

public void SendMessage()
    {
        SmtpClient client = new SmtpClient();

        client.Send(Message);
        client.Dispose(); 
        DisposeAttachments(); 
    }

Как правильно распоряжаться клиентом?

Обновление: для ответа на вопрос Джонса, вот распоряжениефункциональность вложений:

private void DisposeAttachments()
{
    foreach (Attachment attachment in Message.Attachments)
    {
        attachment.Dispose();
    }
    Message.Attachments.Dispose();
    Message = null; 
}

Последнее обновление полный список классов (сокращенно)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;

public class Mailer
    {
    public MailMessage Message
    {
        get;
        set;
    }

    public Mailer(MailMessage message)
    {
        this.Message = message; 
    }

    public void SendMessage()
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        }
        DisposeAttachments(); 
    }

    private void DisposeAttachments()
    {
        foreach (Attachment attachment in Message.Attachments)
        {
            attachment.Dispose();
        }
        Message.Attachments.Dispose();
        Message = null; 
    }
    }

Ответы [ 6 ]

47 голосов
/ 06 мая 2010
public void SendMessage()
{
    using (SmtpClient client = new SmtpClient())
    {
        client.Send(Message);
    }
    DisposeAttachments(); 
}

Таким образом, клиент будет удален, даже если во время вызова метода Send возникнет исключение. Вам очень редко нужно явно вызывать Dispose - это почти всегда должно быть в операторе using.

Тем не менее, неясно, как вложения участвуют здесь. Ваш класс реализует IDisposable сам? Если это так, то это, вероятно, место для удаления вложений, которые предположительно являются переменными-членами. Если вам нужно быть абсолютно уверенным, что они находятся здесь, вам, вероятно, понадобится:

public void SendMessage()
{
    try
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        }
    }
    finally
    {
        DisposeAttachments(); 
    }
}
12 голосов
/ 06 мая 2010

Класс SmtpClient в .NET 4.0 теперь реализует IDisposable, в то время как класс SmtpClient в .NET 2.0 не имеет этого интерфейса (как отметил Дарин). Это серьезное изменение в среде, и вы должны предпринять соответствующие действия при переходе на .NET 4.0. Однако это можно исправить в своем коде до перехода на .NET 4.0. Вот пример такого:

var client = new SmtpClient();

// Do not remove this using. In .NET 4.0 SmtpClient implements IDisposable.
using (client as IDisposable)
{
    client.Send(message);
} 

Этот код будет правильно скомпилирован и работать как в .NET 2.0 (+3.0 и 3.5), так и в .NET 4.0.

7 голосов
/ 06 мая 2010
using (SmtpClient client = new SmtpClient())
{
    client.Send(Message);
    DisposeAttachments(); 
}

Интересно - в отличие от .NET 3.5, SmtpClient реализует IDisposable в .NET 4.0, изучая новые вещи каждый день.

5 голосов
/ 06 мая 2010

Я бы сделал что-то подобное:

class Attachments : List<Attachment>, IDisposable
{
  public void Dispose()
  {
    foreach (Attachment a in this)
    {
      a.Dispose();
    }
  }
}

class Mailer : IDisposable
{
  SmtpClient client = new SmtpClient();
  Attachments attachments = new Attachments();

  public SendMessage()
  {
    [... do mail stuff ...]
  }

  public void Dispose()
  {
    this.client.Dispose();
    this.attachments.Dispose();
  }
}


[... somewhere else ...]
using (Mailer mailer = new Mailer())
{
  mailer.SendMail();
}

Это позволит повторно использовать объект SmtpClient, если вы хотите отправлять несколько писем.

2 голосов
/ 06 мая 2010

Это более точное решение, которое пройдет проверку кода на наличие кода (и утилита всегда будет вызываться при сбое отправки):

public void SendMessage()
{
    using (SmtpClient client = new SmtpClient())
    {   
        client.Send(Message);
        DisposeAttachments(); 
    }
}
0 голосов
/ 19 октября 2013
public void SendMessage()
{
    try
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        client.dispose()

        }
    }
    finally
    {
        DisposeAttachments(); 
    }
}
...