您的位置:首页 > 其它

优化.NET访问Active Directory的性能

2008-11-18 23:11 375 查看
从Active Directory获取大量对象时应特别注意,一不小心,就会掉入性能瓶颈甚至引起内存泄漏。本文提供了一个关于.NET访问Active Directory的优化例子。

1.获取对象的属性值 DirectoryEntry.Properties

获取一个DirectoryEntry对象后,我们就开始检索它的属性值;习惯了用foreach的朋友一般会这样写:

DirectoryEntry entry = //

foreach(Property property in entry.Properties)

{

if(property.Name == //)

//

}
事实上,System.DirectoryService.PropertyCollection内部包含了一个HashTable用于键值对访问,并且在索引器中,对未包含的键,创建一个新的PropertyValueCollection对象并加入到HashTable中。

所以,我们可以放心地直接写下:

string propertName = //

object value = entry.Properties[propertName].Value;

对这个新建的PropertyValueColletion,它的Value属性定义同样保证了访问的健壮性,这是它的源代码:

public object Value

{

get

{

if (base.Count == 0)

{

return null;

}

if (base.Count == 1)

{

return base.List[0];

}

object[] array = new object[base.Count];

base.List.CopyTo(array, 0);

return array;

}

}

这样,代码中不需要去调用entry.Properties.Contains方法,而直接使用以下代码就可以高效地访问DirectoryEntry对象的属性了:

object value = entry.Properties[propertyName].Value;

if ( value != null )

{

//

}

在测试中,查询两万个对象的属性值时,可以节省90秒左右的时间。

2.构建搜索器 DirectorySearcher

使用这个类应注意三点:

(1)对搜索结果的缓存。它默认的CacheResults为true,如果你不需要,应记得将它设置为false,否则一大块空间就浪费了。

(2)仅搜索已赋值的Property。PropertyNamesOnly默认为false,会搜索所有的Property返回多于你想要的对象,记得将它设置为true。

(3)可以在其构造函数中指定PropertyName数组,只搜索包含PropertyName的对象。

下面的例子是搜索包含UserName和Password属性并且属性已赋值的对象:

DirectorySearcher searcher = new DirectorySearcher(

entry,

"username=*",

new string[] { "UserName", "Password", });

searcher.PropertyNamesOnly = true;

SearchResultCollection results = searcher.FindAll();

3.遍历和释放结果集 SearchResultCollection

foreach对于SearchResultCollection的访问是更高效的方式,这是因为,SearchResultCollection的内部使用ArrayList进行集合的索引访问,在第一次加载ArrayList时,它调用迭代器将所有的SearchResult对象创建并装箱到ArrayList中,当进行SearchResultCollection[int index]访问时,它对ArrayList中的对象进行拆箱操作。下面是SearchResultCollection构建InnerList的源代码:

private ArrayList InnerList

{

get

{

if (this.innerList == null)

{

this.innerList = new ArrayList();

IEnumerator enumerator = new ResultsEnumerator(this, this.rootEntry.GetUsername(), this.rootEntry.GetPassword(), this.rootEntry.AuthenticationType);

while (enumerator.MoveNext())

{

this.innerList.Add(enumerator.Current);

}

}

return this.innerList;

}

}

而foreach是直接调用迭代器创建和返回一个SearchResult对象,避免了装箱与拆箱的过程。

应严重注意的是:SearchResultCollection是未托管资源,而且会占用大量的内存,需要获取大量对象的属性时,推荐使用集合来保存所需的属性值,完成之后立即调用SearchResultCollection.Dispose()来对它进行释放,否则,会导致内存泄露。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: