我试图创建DirectoryEntry的实例,以便可以使用它来测试将传递给DirectoryEntry的一些代码。但是,尽管进行了很多尝试,我仍然找不到一种实例化DE并将其初始化为PropertyCollection的方法。
我有以下代码是从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"});
我希望我已经错过了一些东西,因为我是在愤怒中使用反射的新手。
最佳答案
我不熟悉DirectoryEntry本身,但是我非常喜欢Adapter模式进行测试。您不得不做这样的事情很烦人,但是代码本身很琐碎,可以将这些类放在项目文件夹中以将其隐藏在远离主项目的地方。
例如,我有一个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; } }
}