Wil*_*ler 1 c# generics reflection dependency-injection interface
我写了一个泛型类型:IDirectorySource<T> where T : IDirectoryEntry
,我使用的是通过我的接口的对象来管理Active Directory中的条目,其中:IGroup
,IOrganizationalUnit
,IUser
.
这样我就可以写下面的内容:
IDirectorySource<IGroup> groups = new DirectorySource<IGroup>(); // Where IGroup implements `IDirectoryEntry`, of course.`
foreach (IGroup g in groups.ToList()) {
listView1.Items.Add(g.Name).SubItems.Add(g.Description);
}
Run Code Online (Sandbox Code Playgroud)
从IDirectorySource<T>.ToList()
方法中,我使用反射来找出类型参数的适当构造函数T
.但是,由于T
给定了一个接口类型,它根本找不到任何构造函数!
当然,我有一个internal class Group : IGroup
实现IGroup
接口的.无论我多么努力,我都无法弄清楚如何通过我的实现类从我的界面中获取构造函数.
[DirectorySchemaAttribute("group")]
public interface IGroup {
}
internal class Group : IGroup {
internal Group(DirectoryEntry entry) {
NativeEntry = entry;
Domain = NativeEntry.Path;
}
// Implementing IGroup interface...
}
Run Code Online (Sandbox Code Playgroud)
在ToList()
我的IDirectorySource<T>
接口实现方法中,我寻找T
如下构造函数:
internal class DirectorySource<T> : IDirectorySource<T> {
// Implementing properties...
// Methods implementations...
public IList<T> ToList() {
Type t = typeof(T)
// Let's assume we're always working with the IGroup interface as T here to keep it simple.
// So, my `DirectorySchema` property is already set to "group".
// My `DirectorySearcher` is already instantiated here, as I do it within the DirectorySource<T> constructor.
Searcher.Filter = string.Format("(&(objectClass={0}))", DirectorySchema)
ConstructorInfo ctor = null;
ParameterInfo[] params = null;
// This is where I get stuck for now... Please see the helper method.
GetConstructor(out ctor, out params, new Type() { DirectoryEntry });
SearchResultCollection results = null;
try {
results = Searcher.FindAll();
} catch (DirectoryServicesCOMException ex) {
// Handling exception here...
}
foreach (SearchResult entry in results)
entities.Add(ctor.Invoke(new object() { entry.GetDirectoryEntry() }));
return entities;
}
}
private void GetConstructor(out ConstructorInfo constructor, out ParameterInfo[] parameters, Type paramsTypes) {
Type t = typeof(T);
ConstructorInfo[] ctors = t.GetConstructors(BindingFlags.CreateInstance
| BindingFlags.NonPublic
| BindingFlags.Public
| BindingFlags.InvokeMethod);
bool found = true;
foreach (ContructorInfo c in ctors) {
parameters = c.GetParameters();
if (parameters.GetLength(0) == paramsTypes.GetLength(0)) {
for (int index = 0; index < parameters.GetLength(0); ++index) {
if (!(parameters[index].GetType() is paramsTypes[index].GetType()))
found = false;
}
if (found) {
constructor = c;
return;
}
}
}
// Processing constructor not found message here...
}
Run Code Online (Sandbox Code Playgroud)
我的问题是T
永远是一个interface
,所以它永远不会找到一个构造函数.
有没有比循环我的所有程序集类型更好的方法来实现我的界面?
我不关心重写我的代码,我想在第一个地方做到这一点,这样我就不需要一次又一次地回来.
编辑#1
根据Sam的建议,我现在将遵循IName
和Name
惯例.但是,是我还是有办法改进我的代码?
谢谢!=)
你有几种可能性.
class DirectorySource<T>: IDirectorySource<T> {
public DirectorySource(ISearcher<T> searcher) {
Searcher = searcher;
}
public IList<T> ToList() {
string filter = "...";
return Searcher.FindAll(filter);
}
}
class GroupSearcher: ISearcher<Group> {
public IList<Group> FindAll(string filter) {
entries = ...
var entities = new List<Group>();
foreach (var entry in entries)
entities.Add(new Group(entry.GetDirectoryEntry());
return entities;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您将像这样实例化DirectorySource:
IDirectorySource<Group> groups = new DirectorySource<Group>(new GroupSearcher());
Run Code Online (Sandbox Code Playgroud)
编辑: 你也可以使用lambda表达式.
class DirectorySource<T>: IDirectorySource<T> {
// Or you could put the parameter in constructor if this is not the only place
// where you create new instances of T
public IList<T> ToList(Func<DirectoryEntry, T> create) {
...
foreach (var entry in entries)
entities.Add(create(entry.GetDirectoryEntry()));
return entities;
}
}
IList<Group> groups = new DirectorySource<Group>().ToList(entry => new Group(entry));
Run Code Online (Sandbox Code Playgroud)
关于班级责任等,您是否对每种支持类型进行了特殊处理,例如:Change(T)
方法(或任何其他)?如果是这样,那么我仍然会重构和使用IDirectoryEntryManager<T>
(或其他一些名称)知道如何处理适当的类型.DirectorySource
然后可以使用该类来操纵具体类型,而不是负担不属于那里的细节.