赏梅斋

关注微软技术

博客园 首页 新随笔 联系 订阅 管理
  90 Posts :: 2 Stories :: 171 Comments :: 32 Trackbacks

公告

可以采用某些编码技术来确保释放对象。这些技术包括在代码中使用以下内容:

  • Dispose 方法

  • using 语句

  • trycatchfinally

Dispose 与 Close 方法的用途

SPWeb 对象和 SPSite 对象的 DisposeClose 方法作用相同。Dispose 方法调用对象的 Close 方法。我们建议调用 Dispose 方法,而不是调用 Close 方法,因为 SPWebSPSite 对象实现 IDisposable 接口,标准 .NET Framework 垃圾收集调用 Dispose 方法从内存中释放与对象关联的任何资源。

using 语句

通过使用 Microsoft Visual C# 和 Visual Basic using 语句,可以自动释放实现 IDisposable 接口的 SharePoint 对象。

以下代码提供了示例。

 

String str;

using(SPSite oSPsite = new SPSite("http://www.msiw.net/"))
{
  using(SPWeb oSPWeb = oSPSite.OpenWeb())
   {
       str = oSPWeb.Title;
       str = oSPWeb.Url;
   }

 

利用 using 语句可以大大简化代码。公共语言运行库会将 using 语句转换为 try 和 finally 块,并且会为您释放实现 IDisposable 接口的任何对象。但是,在许多情况下,using 语句并不可取,或者必须慎用并要了解运行库所执行的操作。以下代码示例显示了一个不希望运行库为您构建 finally 块和释放对象的情况。在此情况下,SPContext 返回 SPWeb 对象。

// Do not do this. Dispose() is automatically called on SPWeb.
using( SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) { ... }

 

SPContext 对象由 SharePoint 框架进行管理并且不应该在代码中明确释放。SPContext.SiteSPContext.Current.SiteSPContext.WebSPContext.Current.Web 返回的 SPSiteSPWeb 对象也是如此。

 

每当在同一行上合并 SharePoint 对象模型调用时,必须慎重并知道运行库所做的操作。这种情况引发的泄露最难找到。

在以下代码示例中,SPSite 对象会被实例化但不被释放,因为运行库会确保仅释放 OpenWeb 返回的 SPWeb 对象。

 

void CombiningCallsLeak()
{
    using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
    {
        // ... New SPSite will be leaked.
    } // SPWeb object web.Dispose() automatically called.
}

 

通过将一个 using 语句嵌套在另一个语句中,可以解决此问题。

 

void CombiningCallsBestPractice()
{
    using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
    {
        using (SPWeb web = siteCollection.OpenWeb())
        {
        // Perform operations on site.
        } // SPWeb object web.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

 

如果不对 SPSite 对象执行任何操作,则可以像在以下代码示例中那样更加简洁地编写此内容。

 

void CombiningCallsBestPractice()
{
    using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
    using (SPWeb web = siteCollection.OpenWeb())
        {
        // Perform operations on site.
        } // SPWeb object web.Dispose() automatically called; SPSite object
          // siteCollection.Dispose() automatically called.
}

 

在其他情况下,必须构建自己的 trycatchfinally 块。需要处理异常并因此必须包括 catch 块的情况就是最明显的示例。

try、catch 和 finally 块

每当需要处理异常时,使用 trycatchfinally 块显然是有意义的。try/catch 块中的任何代码都应该具有 finally 控制子句,这样可以确保释放实现 IDisposable 的对象。请注意,在以下代码示例中,应该在 catch 块中填充处理异常的代码。决不要将 catch 块留空。另外请记下在释放之前测试 null 的最佳实践。

 

String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;

try
{
   oSPSite = new SPSite("http://server/");
   oSPWeb = oSPSite.OpenWeb(..);

   str = oSPWeb.Title;
}
catch(Exception e)
{
   // Handle exception, log exception, etc.
}
finally
{
   if (oSPWeb != null)
     oSPWeb.Dispose();

   if (oSPSite != null)
      oSPSite.Dispose();
}

 

foreach 块内创建可释放的对象时,为了避免潜在泄露,必需使用 Tryfinally 块或 using 语句,如以下代码示例中所示。

 

public static void SPSiteCollectionForEachBestPractice()
{
     string sUrl = "http://www.msiw.net/";
 
      using (SPSite siteCollectionOuter = new SPSite(sUrl))
     {
         SPWebApplication webApp = siteCollectionOuter.WebApplication;
         SPSiteCollection siteCollections = webApp.Sites;

                  SPSite siteCollectionInner = null;
                  foreach (siteCollectionInner in siteCollections)
             {
                      try  // Should be first statement after foreach.
                      {
                          Console.WriteLine(siteCollectionInner.Url);
                          // Exception occurs here.
                      }
                      finally
                      {
                          if(siteCollectionInner != null)
                          siteCollectionInner.Dispose();
                      }
             }
     } // SPSite object siteCollectionOuter.Dispose() automatically called.
 }

 

Response.Redirect 以及 try 块、catch 块、finally 块和 using 语句

try 块中调用 Response.Redirect 之后,将会执行 finally 块。Response.Redirect 最终会生成 ThreadAbortException 异常。出现此异常时,运行库会执行所有 finally 块,然后结束线程。但是,因为 finally 块可能会执行无限制的计算或取消 ThreadAbortException,所以该线程未必会结束。因此,必须先释放对象,然后才能重定向或传输处理。如果代码必须重定向,请按照与以下代码示例类似的方法来实现代码。

 

String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;

try
{
   oSPSite = new SPSite("http://www.msiw.netserver/");
   oSPWeb = oSPSite.OpenWeb(..);

   str = oSPWeb.Title;
   if(bDoRedirection)
   {
       if (oSPWeb != null)
          oSPWeb.Dispose();
   
       if (oSPSite != null)
          oSPSite.Dispose();

       Response.Redirect("newpage.aspx");
   }
}
catch(Exception e)
{
}
finally
{
   if (oSPWeb != null)
     oSPWeb.Dispose();

   if (oSPSite != null)
      oSPSite.Dispose();
}

 

因为 using 语句会命令运行库创建 finally 块,所以每当在 using 语句内使用 Response.Redirect 时,请确保正确释放对象。以下代码示例演示如何执行此操作。

 

using (SPSite oSPSite = new SPSite("http://server/"))
using (SPWeb oSPWeb = oSPSite.OpenWeb(..))
{
    if (bDoRedirection)
        Response.Redirect("newpage.aspx");
}

 

缩短长时间对象保留期的建议

通过遵循以下常规建议,可以缩短 SharePoint 对象的长时间保留期。

  • 如果用 new 运算符创建对象,请确保用于创建的应用程序释放该对象。

 

良好的编码实践 #1

明确释放

 

void CreatingSPSiteExplicitDisposeNoLeak()
{
    SPSite siteCollection = null;
    try
    {
        siteCollection = new SPSite("http://www.msiw.net/");
    }
    finally
    {
        if (siteCollection != null)
            siteCollection.Dispose();
    }
}

 

良好的编码实践 #2

自动释放

CreatingSPSiteWithAutomaticDisposeNoLeak()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
    } // SPSite object siteCollection.Dispose() is called automatically.
}

 

释放由返回其他 SPWeb 对象的 SharePoint 方法(如 OpenWeb())所创建的项。

 

良好的编码实践

 

void OpenWebNoLeak()
{
    using (SPSite siteCollection = new SPSite("http://www.msiw.net/"))
    {
        using (SPWeb web = siteCollection.OpenWeb())
        {
        } // SPWeb object web.Dispose() automatically called.
    }  // SPSite object siteCollection.Dispose() automatically called.
}

 

  • 不要在线程之间共享任何 SPRequest 对象(以及通过扩展共享任何包含对 SPRequest 对象的引用的对象)。不支持以下性质的任何编码技术:在两个或更多个线程之间共享 SPRequest 对象,或者在一个线程上创建 SPRequest 对象而在另一个线程上释放该对象。这意味着,无法在静态变量中存储任何包含对 SPRequest 对象的引用的对象。因此,不要将实现 IDisposable 的 SharePoint 对象(例如 SPWebSPSite)存储在静态变量中。

  •  

     

    posted on 2011-02-11 17:51 赏梅斋 阅读(...) 评论(...) 编辑 收藏