C#如何正确处置SmtpClient?
VS 2010代码分析报告如下: 警告4 CA2000:Microsoft。可靠性:在方法“Mailer.SendMessage()”中,对象“client”未沿所有异常路径释放。在对象“客户端”上调用System.IDisposable.Dispose,然后将其所有引用都超出范围 我的代码是:C#如何正确处置SmtpClient?,c#,.net-4.0,C#,.net 4.0,VS 2010代码分析报告如下: 警告4 CA2000:Microsoft。可靠性:在方法“Mailer.SendMessage()”中,对象“client”未沿所有异常路径释放。在对象“客户端”上调用System.IDisposable.Dispose,然后将其所有引用都超出范围 我的代码是: public void SendMessage() { SmtpClient client = new SmtpClient(); client.Send(Me
public void SendMessage()
{
SmtpClient client = new SmtpClient();
client.Send(Message);
client.Dispose();
DisposeAttachments();
}
我应该如何正确处置客户机
更新:要回答Jon的问题,以下是dispose attachments功能:
private void DisposeAttachments()
{
foreach (Attachment attachment in Message.Attachments)
{
attachment.Dispose();
}
Message.Attachments.Dispose();
Message = null;
}
上次更新完整类列表(简称)
有趣-与.NET3.5相反,它在.NET4.0中实现,每天学习新事物
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();
}
}
这是一个更整洁的解决方案,将通过代码警察测试(如果发送失败,将始终调用dispose):
我会这样做:
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();
}
类附件:列表,IDisposable
{
公共空间处置()
{
foreach(本文件附件a)
{
a、 处置();
}
}
}
类邮件器:IDisposable
{
SmtpClient=新的SmtpClient();
附件=新附件();
公共发送消息()
{
[…发邮件…]
}
公共空间处置()
{
this.client.Dispose();
this.attachments.Dispose();
}
}
[…其他地方…]
使用(Mailer-Mailer=new-Mailer())
{
SendMail();
}
如果您想发送多封邮件,这将允许重用SmtpClient对象。现在.NET 4.0中的
SmtpClient
类实现了IDisposable
,而.NET 2.0中的SmtpClient
类缺少此接口(如Darin所述)。这是框架中一个突破性的更改,在迁移到.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下正确编译和运行。我最初的问题是间歇性发送失败。
public void SendMessage()
{
try
{
using (SmtpClient client = new SmtpClient())
{
client.Send(Message);
client.dispose()
}
}
finally
{
DisposeAttachments();
}
}
例如,第一个Send()
成功,第二个Send()
失败,第三个Send()
成功。
起初我认为我处理得不好。
所以我求助于使用()
无论如何,后来我添加了
UseDefaultCredentials=false,
并且Send()
最终变得稳定。我仍然保留了using()
函数。@JL:Hmm。。。仍然感觉附件应该作为正在处理的实例的一部分进行处理,可能是这样。您的DisposeAttachments
消息也意味着您以后无法获取消息,这听起来有点奇怪…消息发送后,我不需要消息或附件的实例。我应该实现析构函数吗?SmtpClient
不实现IDisposable
:-)JFYI:请记住,如果与smtp服务器的连接关闭,在调用.Dispose()
,而不是.Send()
,有时会引发异常。因此,将整个using
块保存在try catch
中,而不仅仅是Send()
调用。@JonSkeet当然你是对的。只是想强调一下,如果要捕获连接错误,请将“dispose()”调用保留在TRY块中。这不是人们所期望的。@Darin的主要好处是SMTP客户端现在终于在dispose中发送了QUIT命令:)对此非常高兴@达林:WTF??SmtpClient在.NET 4.0中实现IDisposable???这是一个相当大的突破性变化。这很痛。@Steven,是的,它似乎终于通过向服务器发送QUIT命令正确地关闭了连接。Tsk,Tsk,Tsk,IDisposable滥用。System.Net团队没有羞耻感。请注意-如果您没有使用Network delivery方法,并且没有设置Host属性,那么Dispose方法将抛出InvalidOperationException@JL-您不应该手动处理附件,而应该处理邮件消息本身,邮件消息本身会处理附件、备用视图和其他部分。确实如此,但在旧版本(在.net 4.0之前)中,SmtpClient没有实现处理方法。请尝试使用一些描述提供您的代码答案调用Dispose()
在中使用块似乎是完全多余的。但是。。。它是否有助于正确处理客户端?因为早期3.5版本的真正问题是它不向服务器发送退出消息,导致服务器一直等待通信。这显然会导致重新连接到同一服务器时出现问题。@nyrguds:这个构造当然不会解决这个问题。顺便说一句,在编译时,您必须记住“as”是一个安全强制转换,在失败时返回null。这意味着,当然,它将在4.0之前编译,但如果强制转换失败,它可能会在该点上使客户端
为空,并在那之后立即导致空引用错误。@nyrguds:与其想象,不如像我写下这个答案之前那样测试它?
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();
}
var client = new SmtpClient();
// Do not remove this using. In .NET 4.0 SmtpClient implements IDisposable.
using (client as IDisposable)
{
client.Send(message);
}
public void SendMessage()
{
try
{
using (SmtpClient client = new SmtpClient())
{
client.Send(Message);
client.dispose()
}
}
finally
{
DisposeAttachments();
}
}