代码之家  ›  专栏  ›  技术社区  ›  Will Marcouiller

通过反射获取接口类型的构造函数,有比通过类型循环更好的方法吗?

  •  1
  • Will Marcouiller  · 技术社区  · 14 年前

    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);
    }
    

    IDirectorySource<T>.ToList() 方法,我使用反射为类型参数找到合适的构造函数 T . 然而,自从 类型,它根本找不到任何构造函数!

    当然,我有一个 internal class Group : IGroup 它实现了 接口。不管我怎么努力,我都不知道如何通过我的实现类将构造函数从接口中取出。

    [DirectorySchemaAttribute("group")]
    public interface IGroup {
    }
    
    internal class Group : IGroup {
        internal Group(DirectoryEntry entry) {
            NativeEntry = entry;
            Domain = NativeEntry.Path;
        }
        // Implementing IGroup interface...
    }
    

    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...
    }
    

    我的问题是 T interface ,所以它永远找不到构造函数。

    我不在乎重写我的一段代码,我想一开始就把它做好,这样我就不需要一次又一次地回来。

    编辑#1

    IName Name

    3 回复  |  直到 14 年前
        1
  •  5
  •   Patko    14 年前

    你有几种可能。

    
    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;   
      } 
    }
    

    然后您将实例化DirectorySource,如下所示:

    IDirectorySource<Group> groups = new DirectorySource<Group>(new GroupSearcher());
    
    • ... :)

    也可以使用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));
    

    Change(T) 方法(或任何其他方法)?如果是这样的话,我仍然会重构并使用 IDirectoryEntryManager<T> (或其他名称)知道如何处理适当的类型。 DirectorySource

        2
  •  3
  •   Samuel Neff    14 年前

    您可以遍历程序集中的所有类,并找到一个实现接口的类。当您发现多个实现时,您需要决定要做什么。

    或者,如果有一致的命名方案,则可以从接口名生成类名。

        3
  •  2
  •   Yury Tarabanko    14 年前

    您可以创建特殊的属性到点实现类型,而无需依赖命名约定。

    [AttributeUsage(AttributeTargets.Interface)]
    public class ImplementingTypeAttribute: Attribute
    {
        public Type ImplementingType { get; set; }
    
        public ImplementingTypeAttribute(Type implementingType)
        {
            ImplementingType = implementingType;
        }
    }