2008年6月15日,星期日

处置SharePoint双色球推荐一注-它们的作用't tell you

如果您是SharePoint开发人员,并且发现自己定期编写代码以与SPListItem双色球推荐一注一起使用,则此处的一些信息可能会帮助您在某些情况下以更简洁的方式来考虑代码。 有趣的是,在任何关键论文/文章中都没有提到这一点-我可以想到一个很好的理由(我们将要介绍),但是在我看来,这是一种安全的技术。但是,如果您还有其他想法,我很想听听您的意见。

现在,大多数开发人员都精通编写高效SharePoint代码所需的技术(本文结尾列出了关键资源),特别是在处置您代码创建的任何SPSite / SPWeb双色球推荐一注方面。事实是,必须时刻谨记处理这些双色球推荐一注有时会限制我们编写代码的方式-考虑以下简化示例:

public void DoSomething()
{
SPList list = getList();

// 做 something with list..
foreach (SPListItem item in list.Items)
{
processItem(item);
}

// ** PROBLEM - how 做 we now dispose of the SPSite/SPWeb objects we created earlier? **
}

private SPList getList()
{
// 能够't dispose of these objects 这里 if we're returning a list - we'll be 在 tempting to use
// objects which have already been disposed of..
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

return list;
}


这里的问题是,我们以与需要处置它们的方法不同的方式创建了SPSite / SPWeb双色球推荐一注-在编写库代码时,这可能会发生很多。为了扩展此示例,下面是我经常使用的一种模式,以确保以最有效的方式获取双色球推荐一注-使用SPContext(如果存在),但如果没有则实例化它们(即,从事件接收器调用代码,控制台应用等):


public void DoSomething()
{
bool bDisposalsRequired = false;

// get list from SPContext if we have one..
SPList list = getListFromContext();
if (list == null)
{
// otherwise get list from objects we create..
list = getInstantiatedList();
bDisposalsRequired = true;
}

// 做 something with list..
foreach (SPListItem item in list.Items)
{
processItem(item);
}

if (bDisposalsRequired)
{
// ** PROBLEM - how 做 we now dispose of the SPSite/SPWeb objects we created earlier? **
}
}

private SPList getInstantiatedList()
{
// 能够't dispose of these objects 这里 if we're returning a list - we'll be 在 tempting to use
// objects which have already been disposed of..
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

return list;
}

private SPList getListFromContext()
{
SPContext currentContext = SPContext.Current;
SPList list = null;

if (currentContext != null)
{
list = currentContext.Site.AllWebs["MyWeb"].Lists["MyList"];
}

return list;
}


当代码开始变得像这样复杂时,我们开始 想要一种简单的方式来处理我们在其他地方创建的双色球推荐一注。我可能会对此提出警告,但是如果您不仅使用另一种方法创建了SPSite / SPWeb双色球推荐一注,还会发生什么呢? ?突然正确地布置双色球推荐一注比白皮书中给出的示例要复杂得多。 

现在,精明的SharePoint开发人员可能会认为"等等,SPList有一个ParentWeb双色球推荐一注(而SPListItem有一个ParentList双色球推荐一注!),如果我按层次结构进行这种处理会怎样?"-此代码如下所示:


if (bDisposalsRequired)
{
list.ParentWeb.Dispose();
list.ParentWeb.Site.Dispose();
}


现在我们如何知道正确的物体已被处置?这些双色球推荐一注与我们之前使用的双色球推荐一注相同吗?或者SharePoint已使用以下引用填充了这些属性: 不同 双色球推荐一注,这意味着我们已经将原始双色球推荐一注保留下来并且可能会遇到可扩展性问题?

好吧,好消息是这些是相同的双色球推荐一注,因此以这种方式处理 处理您创建的双色球推荐一注。我们可以通过使用System.Object的GetHashCode()方法比较双色球推荐一注来告诉我们:


private void compareObjects()
{
SPSite site = new SPSite("http://cob.blog.dev");
SPWeb web = site.OpenWeb("/MyWeb");
SPList list = web.Lists["MyList"];

SPWeb parentWeb = list.ParentWeb;



// no message displayed..
Debug.Assert(parentWeb.GetHashCode() != web.GetHashCode(), "Objects are not same!");


// create a *new* SPWeb object and compare it to our other reference..
web = site.OpenWeb("/MyWeb");

// message IS displayed..
Debug.Assert(parentWeb.GetHashCode() != web.GetHashCode(), "Objects are not same!");
}


从中我们看到的是,存储在list.ParentWeb属性中的SPWeb双色球推荐一注与我们创建的原始SPWeb双色球推荐一注具有相同的哈希码,但是如果我们创建同一网站的新实例,则其具有不同的哈希码。这表明第一个比较中的双色球推荐一注是相同的-因此,通过ParentWeb引用处理它们确实会处理我们创建的双色球推荐一注。开心的日子-我们找到了 能够 以一种可能更具逻辑性和可读性的方式来分解我们的代码。


注意事项

那么,为什么在任何已发布的指南中都没有提及呢?很好,在整个代码中使用此技术之前,您应该考虑到以这种方式编写代码时,我们实际上是依靠当前SharePoint API的内部实现细节。如果Microsoft要在Service Pack(或SharePoint的下一版本)中对此进行更改,则我们的代码可能不再能正确处理双色球推荐一注。我建议您自己考虑一下(尤其是因为您可能得出与我不同的结论),但是我建议这种更改不太可能发生。原因是SharePoint团队本身需要消除任何不必要的SPSite / SPWeb双色球推荐一注,因此 当然 有道理,用于获取SPList的相同SPWeb实例用于填充ParentWeb变量。创建一个额外的实例将使API 高效。在此基础上,我个人很高兴以这种方式编写代码。如果您认为我错了(我不能保证我没有错),那么我当然希望收到您的来信。

在下一篇文章中,我还将讨论超越MSDN示例的想法,并尝试以更“企业”或“模式”的方式编写SharePoint数据访问代码。敬请期待更多。


处置SharePoint双色球推荐一注-必读

张贴者 Chris O'Brien 21:02  

标签:

4条评论:

匿名 said...

问题的一部分是Microsoft不一致使用IDisposable接口。 SPWeb实现了它,但SPList却没有,即使两者都可以包含对SPRequest双色球推荐一注的引用。这不是唯一不实现IDisposable的类可以创建双色球推荐一注的情况, 需要处理。尽管您可以使用Reflector找出导致SPRequest实例化的方法,但您不必依赖于实现细节。

通过将可能需要的任何SPWeb和SPSite实例化,并在最后一刻将其废弃,可以在某种程度上避免这种情况,但这意味着您将在所需的双色球推荐一注上持有比所需时间更长的双色球推荐一注,并在代码运行时使用比所需资源更多的资源。 。不过,它仍然胜过其他选择。

2008年6月15日在22:08
匿名 said...

克里斯〜

我发布了一种可能的替代方法 这里。让我知道你的想法。

干杯〜
基思

2008年6月16日在04:19
托霍纳斯说过...

感谢您的好帖子。

问题在于这根本无法扩展。

您已经谈到了为SharePoint编写库代码的问题,这就是我在下面谈论的问题。

在我看来,“校正”是不可能的,因为有时您应该处置双色球推荐一注,而有时则不应该。 (请记住,我在谈论的是库代码,其中该方法不了解SPWeb和SPSite的构造方式)


您的调用堆栈越深,获得的可能性就越大。

在您的示例中,您只有两个级别。您的主要方法,然后使用两个辅助方法获得双色球推荐一注。而且,您必须派出一个标志来知道何时处置或不处置。

试想一下,您有更多的嵌套调用,并且您看到它无法完成。

我说无法完成的原因是,我们被告知仅通过访问一些 属性 已创建OM中的新SPWeb双色球推荐一注,并且由OM的客户来处理这些双色球推荐一注。

而且由于OM正在缓存所有引用并返回相同的实例(如您在GetHashCode()示例中显示的那样),所以我们甚至无法执行此操作,因为我们可能会处理一个双色球推荐一注,该双色球推荐一注以后将在另一个方法中使用。

当我们在双色球推荐一注上调用dispose时,ObjectModel对此一无所知,因此它的内部成员仍设置为同一双色球推荐一注,但现在此双色球推荐一注已被废弃!

不幸的是,OM坏了。

唯一安全的方法是永远不要处置任何双色球推荐一注,除非您已明确创建了它们。

我正在考虑在OM的顶部编写一个外观,该外观将引用计数返回的所有内容,并且客户端必须随时处理所有内容,直到现在该何时实际调用Dispose。

谢谢
/乔纳斯

2008年6月16日在08:59
克里斯·奥'Brien说过...

有趣的评论-这些都是很好的贡献,谢谢。

基思-我喜欢您的想法,这是我建议的不错选择。但是,一个缺点是,它对于较小的调用栈(如我的示例)非常有效,但与Tojonas的注释类似,对于更复杂的模式则不太好-您需要在方法/类之间传递out参数。在我的结构中,在某种程度上可以避免这种情况,在该结构中,您只需要传递SPList / SPListItem即可进行实际使用。

不过,我不确定乔纳斯指出的深层问题是否是真正的解决方案。我不确定是否可以说OM已损坏,但是围绕API编写库代码确实很棘手。乔纳斯(Jonas),如果您对您的图层有任何进一步的考虑,我想听听更多,但是我也看到那里的班级责任感可能会引起一些有趣的问题。

我有一个后续帖子,很快将针对此类问题展开讨论。

克里斯。

2008年6月16日12:27

发表评论