С# как правильно распоряжаться SmtpClient?
Анализ кода VS 2010 сообщает следующее:
Предупреждение 4 CA2000: Microsoft.Reliability: в методе 'Mailer.SendMessage()' объект 'клиент' не расположен по всем путям исключений. Вызовите System.IDisposable.Dispose на объекте "клиент", прежде чем все ссылки на него выйдут из области видимости.
Мой код:
public void SendMessage()
{
SmtpClient client = new SmtpClient();
client.Send(Message);
client.Dispose();
DisposeAttachments();
}
Как правильно распоряжаться клиентом?
Обновление:, чтобы ответить на вопрос Jons, вот функциональность утилиты вложения:
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;
}
}
Ответы
Ответ 1
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();
}
}
Ответ 2
Класс 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.
Ответ 3
using (SmtpClient client = new SmtpClient())
{
client.Send(Message);
DisposeAttachments();
}
Интересно - вопреки .NET 3.5, SmtpClient реализует IDisposable в .NET 4.0, каждый день изучая новые вещи.
Ответ 4
Я бы сделал что-то вроде этого:
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, если вы хотите отправить несколько писем.
Ответ 5
Это новое решение, которое пройдет тест полицейского кода (и утилита всегда будет вызываться, если "Отправить" ):
public void SendMessage()
{
using (SmtpClient client = new SmtpClient())
{
client.Send(Message);
DisposeAttachments();
}
}
Ответ 6
public void SendMessage()
{
try
{
using (SmtpClient client = new SmtpClient())
{
client.Send(Message);
client.dispose()
}
}
finally
{
DisposeAttachments();
}
}