2011-05-11 19 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

相关问题