C#如何正确处置SmtpClient?

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

VS 2010代码分析报告如下:

警告4 CA2000:Microsoft。可靠性:在方法“Mailer.SendMessage()”中,对象“client”未沿所有异常路径释放。在对象“客户端”上调用System.IDisposable.Dispose,然后将其所有引用都超出范围

我的代码是:

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(); 
    }
}