2011-05-11 20 views
5

我正在嘗試創建一個DirectoryEntry實例,以便我可以使用它來測試一些將通過DirectoryEntry的代碼。但是,儘管嘗試了很多,但我找不到實例化DE並初始化它的PropertyCollection的方法。創建一個用於測試的DirectoryEntry實例

我有以下代碼,它是從another answer on SO採取和修改,它是做同樣的過程,但SearchResult對象。看起來Add方法已被完全禁用,我無法找到調用PropertyCollection上的構造函數來傳遞某些屬性的方法。

using System.Collections; 
using System.DirectoryServices; 
using System.Globalization; 
using System.Reflection; 
using System.Runtime.Serialization; 

public static class DirectoryEntryFactory 
{ 
    const BindingFlags nonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance; 
    const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance; 

    public static DirectoryEntry Construct<T>(T anonInstance) 
    { 
     var e = GetUninitializedObject<DirectoryEntry>(); 

     SetPropertiesField(e); 

     var dictionary = (IDictionary)e.Properties; 
     var type = typeof(T); 
     var propertyInfos = type.GetProperties(publicInstance); 

     foreach (var propertyInfo in propertyInfos) 
     { 
      var value = propertyInfo.GetValue(anonInstance, null); 
      var valueCollection = GetUninitializedObject<PropertyValueCollection>(); 
      var innerList = GetInnerList(valueCollection); 
      innerList.Add(value); 

      var lowerKey = propertyInfo.Name.ToLower(CultureInfo.InvariantCulture); 

      // These both throw exceptions saying you can't add to a PropertyCollection 
      //(typeof(PropertyCollection)).InvokeMember("System.Collections.IDictionary.Add", nonPublicInstance | BindingFlags.InvokeMethod, null, dictionary, new object[] { propertyInfo.Name, value }); 
      //dictionary.Add(lowerKey, propertyCollection); 
     } 

     return e; 
    } 

    private static ArrayList GetInnerList(object propertyCollection) 
    { 
     var propertyInfo = typeof(PropertyValueCollection).GetProperty("InnerList", nonPublicInstance); 
     return (ArrayList)propertyInfo.GetValue(propertyCollection, null); 
    } 

    private static void SetPropertiesField(DirectoryEntry e) 
    { 
     var propertiesField = typeof(DirectoryEntry).GetField("propertyCollection", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 
     propertiesField.SetValue(e, GetUninitializedObject<PropertyCollection>()); 
    } 

    private static T GetUninitializedObject<T>() 
    { 
     return (T)FormatterServices.GetUninitializedObject(typeof(T)); 
    } 
} 

使用旨在

DirectoryEntry e = DirectoryEntryFactory.Construct(new { attr1 = "Hello", attr2 = "World"}); 

我希望我已經錯過了一些東西,因爲我是很新,在憤怒中使用反射。

+0

亞當,你實際上管理與作業性的實施來實現這一點?我有同樣的問題[這裏](http://stackoverflow.com/questions/18056483/mocking-the-properties-property-of-directoryentry)。 – 2013-08-05 12:01:48

回答

3

我對DirectoryEntry本身並不熟悉,但我非常喜歡測試適配器模式。這是一個煩惱,你將不得不做這樣的事情,但代碼本身是微不足道的,這些類可以放在項目文件夾中,以將它們遠離主項目。

例如,我有一個FileInfoAdapter和DirectoryInfoAdapter,用於包裝那些觸及文件系統的類。

FileInfoAdapter:

public class FileInfoAdapter : IFileInfo 
{ 
    private readonly FileSystemInfo _fi; 

    public FileInfoAdapter(string fileName) 
     : this(new FileInfo(fileName)) 
    { } 

    public FileInfoAdapter(FileSystemInfo fi) 
    { 
     _fi = fi; 
    } 

    public string Name { get { return _fi.Name; } } 
    public string FullName { get { return _fi.FullName; } } 
    public bool Exists { get { return _fi.Exists; } } 
} 
+0

我曾考慮過包裝物品,但希望有另一個答案。我想我現在可能會放棄幷包裝它,而不是等待一個完美的解決方案 - 但是知道是否有辦法正確地做到這一點會很有趣。 – 2011-05-12 08:38:58

+0

@Adam - 當涉及到不實現接口的庫代碼時,我認爲適配器沒有任何問題。我使用了很多模式。 – 2011-05-16 16:12:19

相關問題