Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在C中快速搜索特定类或子类的对象#_C#_Reflection_Types - Fatal编程技术网

C# 如何在C中快速搜索特定类或子类的对象#

C# 如何在C中快速搜索特定类或子类的对象#,c#,reflection,types,C#,Reflection,Types,我希望创建一个不同类的对象集合,并且能够快速搜索可以分配给特定类的所有实例,而不必迭代整个列表。我可以使用字典,但是它不能找到所有的子类/接口 public class Parent { } public class Child : Parent { } public class Other { } public class ObjHolder { Dictionary<System.Type, List<object>> objs = new Dicti

我希望创建一个不同类的对象集合,并且能够快速搜索可以分配给特定类的所有实例,而不必迭代整个列表。我可以使用
字典
,但是它不能找到所有的子类/接口

public class Parent {
}

public class Child : Parent {
}

public class Other {
}


public class ObjHolder {
    Dictionary<System.Type, List<object>> objs = new Dictionary<System.Type, List<object>>();

    public void AddObject(object obj) {
        if (!objs.ContainsKey(obj.GetType()) {
            objs[obj.GetType()] = new List<object>();
        }

        objs[obj.GetType()].Add(obj);
    }

    public List<object> GetObjectsOfType<T>() {
        return objs.ContainsKey(typeof(T)) ? objs[typeof(T)] : new List<object>();
    }
}
公共类父类{
}
公共类子级:父级{
}
公共类其他{
}
公共类ObjHolder{
Dictionary objs=新字典();
public void AddObject(object obj){
如果(!objs.ContainsKey(obj.GetType()){
objs[obj.GetType()]=新列表();
}
objs[obj.GetType()].Add(obj);
}
公共列表GetObjectsOfType(){
返回objs.ContainsKey(typeof(T))?objs[typeof(T)]:new List();
}
}
现在,这将对以下方面起到很大的作用:

ObjHolder o = new ObjHolder();
o.AddObject(new Parent());
o.AddObject(new Other());
o.GetObjectsOfType<Parent>(); // Returns only the Parent object    
return objs.Where(x => typeof(T).IsAssignableFrom(x.Key))
           .Select(x => x.Value)
           .ToList<object>();
ObjHolder o=newobjholder();
o、 AddObject(新父对象());
o、 AddObject(新的Other());
o、 GetObjectsOfType();//仅返回父对象
但这在以下情况下不起作用:

ObjHolder o = new ObjHolder();
o.AddObject(new Child());
o.AddObject(new Other());
o.GetObjectsOfType<Parent>(); // Returns an empty list
ObjHolder o=newobjholder();
o、 AddObject(新的子对象());
o、 AddObject(新的Other());
o、 GetObjectsOfType();//返回一个空列表
我希望能够获取可以分配给父对象的所有对象,包括子对象,但代码不会返回它


如果我理解正确,如果B继承A并搜索A,那么您也要返回所有B对象

我会这样做:更改现有的
AddObject
方法,将对象添加到多个集合中。您可以使用
Type.BaseType
属性获取基本类型。在循环中执行此操作,直到到达
object

public void AddObject(object obj) {
    Type type;
    do {
        type = obj.GetType();
        if (!objs.ContainsKey(type) {
            objs[type] = new List<object>();
        }
        objs[type] = obj;
        if(type == typeof(object)) break;
        type = type.BaseType;
    } while(true);
}
public void AddObject(object obj){
类型;
做{
type=obj.GetType();
如果(!objs.ContainsKey(类型){
objs[type]=新列表();
}
objs[type]=obj;
如果(type==typeof(object))中断;
type=type.BaseType;
}虽然(正确);
}

您需要检查缓存列表是否包含类型为
T
的可分配对象。请尝试下面的代码检查此关系

public List<object> GetObjectsOfType<T>()
{
   foreach (var pair in objs)
   {
      if (pair.Key == typeof(T) || typeof(T).IsAssignableFrom(pair.Key))
      {
         return pair.Value;
      }
   }

   return new List<object>();
}
您可以使用该方法确定哪些类可分配给泛型

getObjectSoftType
方法更改为以下内容:

ObjHolder o = new ObjHolder();
o.AddObject(new Parent());
o.AddObject(new Other());
o.GetObjectsOfType<Parent>(); // Returns only the Parent object    
return objs.Where(x => typeof(T).IsAssignableFrom(x.Key))
           .Select(x => x.Value)
           .ToList<object>();
应该是:

objs[obj.GetType()].Add(obj);

所以你想要的是类似于字典的东西。让我们试着一步一步地实现它。我的代码有大量的注释,所以我会让代码来说话。基本上你所要做的就是在你将对象添加到对象夹中时留下面包屑

public class InheritanceInfo
{
    private class InheritanceChain
    {
        /// <summary>
        /// LinkedList which holds inheritance chain from least derived to most derived for a given Type.
        /// </summary>
        private readonly LinkedList<Type> _linkedList = new LinkedList<Type>();

        /// <summary>
        /// Creates an Inheritance chain for a given type which holds information about base types.
        /// </summary>
        /// <param name="t">Type for which inheritance chain will be created.</param>
        public InheritanceChain(Type t)
        {
            Type type = t;
            do
            {
                if (type == typeof(object))
                {
                    break;
                }
                _linkedList.AddFirst(type);
                type = type.BaseType;
            } while (true);
        }

        /// <summary>
        /// First element of LinkedList. This will be used for iteration.
        /// </summary>
        public LinkedListNode<Type> First => _linkedList.First;
    }

    /// <summary>
    /// Dictionary which holds Type vs DerivedTypes information. Basically does the all handling.
    /// </summary>
    private readonly ConcurrentDictionary<Type, SingleStepDerivedTypes> _inheritanceDictionary;

    /// <summary>
    /// InheritanceInfo class holds information about each Type's inheritance tree.
    /// Each Type holds information about one step down the inheritance tree.
    /// Example: public class C:B{}
    ///          public class B:A{}
    ///          public class A  {}
    /// Inheritance infor for class A holds info about only B because C is derived from B and
    /// it is not a direct descendant of A.
    /// </summary>
    public InheritanceInfo() {
        _inheritanceDictionary = new ConcurrentDictionary<Type, SingleStepDerivedTypes>();
    }

    /// <summary>
    /// Updates the given Type inheritance tree info.
    /// </summary>
    /// <param name="type"></param>
    public void Update(Type type) {
        var element = new InheritanceChain(type).First;
        while (element.Next != null) {
            _inheritanceDictionary.AddOrUpdate(element.Value, (_)=>AddValueFactory(element.Next.Value), (_,sdt)=>UpdateValueFactory(element.Next.Value,sdt));
            element = element.Next;
        }
    }

    /// <summary>
    /// Gets all the assignable types for the given type t.
    /// </summary>
    /// <param name="t">Type for which assignable types will be searched.</param>
    /// <returns>All the assignable types for Type t.</returns>
    public IEnumerable<Type> GetAssignables(Type t)
    {
        if(_inheritanceDictionary.TryGetValue(t ,out var derivedTypes) == false) {
            return Array.Empty<Type>();
        }
        var recursive = derivedTypes.GetTypes().SelectMany(tp=>GetAssignables(tp));
        return recursive.Concat(derivedTypes.GetTypes());
    }

    /// <summary>
    /// Add value to the dictionary
    /// </summary>
    /// <param name="t">Type to add to ConcurrentDictionary</param>
    /// <returns>SingleStepDerivedTypes which holds information about derived type t</returns>
    private static SingleStepDerivedTypes AddValueFactory(Type t) {
        var s = new SingleStepDerivedTypes();
        s.Add(t);
        return s;
    }

    /// <summary>
    /// Updates the already created SingleStepDerivedTypes object.
    /// </summary>
    /// <param name="t">Type to add</param>
    /// <param name="sdt">SingleStepDerivedTypes</param>
    /// <returns>Updated SingleStepDerivedTypes.</returns>
    private static SingleStepDerivedTypes UpdateValueFactory(Type t, SingleStepDerivedTypes sdt) {
        sdt.Add(t);
        return sdt;
    }
}



public class SingleStepDerivedTypes
{
    /// <summary>
    /// HashSet which holds information about derived Types.
    /// </summary>
    private readonly HashSet<Type> _singleStepDerivedTypes;

    /// <summary>
    /// Constructor ;)
    /// </summary>
    public SingleStepDerivedTypes() {
        _singleStepDerivedTypes = new HashSet<Type>();
    }

    /// <summary>
    /// Adds a Type to the Derived Type information.
    /// </summary>
    /// <param name="type">Type to add.</param>
    public void Add(Type type) {
        _singleStepDerivedTypes.Add(type);
    }

    /// <summary>
    /// Gets the contained information about types.
    /// </summary>
    /// <returns>IEnumerable of Types contained in this object.</returns>
    public IEnumerable<Type> GetTypes() {
        return _singleStepDerivedTypes;
    }
}
ObjectHolder
的用法与您想要的方式相同

var a = new A();
var b = new B();
var c = new C();
var objectholder = new Objectholder();
objectholder.AddObject(a);
objectholder.AddObject(b);
objectholder.AddObject(c);
// Contains A and B and C
var allA = objectholder.GetObjectsOf<A>().ToArray();
var a=newa();
var b=新的b();
var c=新的c();
var objectholder=新的objectholder();
objectholder.AddObject(a);
objectholder.AddObject(b);
objectholder.AddObject(c);
//包含A、B和C
var allA=objectholder.GetObjectsOf().ToArray();

那么包含子类的其他字典字典呢?这可能意味着太多字典,因为一个类可以实现许多接口,每个接口都有自己的基接口,等等。嗯,这可能是一个好的方向,但是接口呢?我还需要迭代所有接口及其所有基接口,这需要uld最终有点太大…这是一种选择,但也许有更好更有效的方法?对于可以调用的接口。GetInterfaces()在类型变量上。对最特定的类型进行一次调用就足够了,它将包含所有接口,包括基类型的接口。这是一个有趣的想法,但并不完美,因为它仍然需要为每次获取迭代所有添加的类型。如果不想迭代所有类型,则需要将所有对象添加到相同的基类型。I这是一个有趣的想法,但并不完美,因为它仍然需要为每次获取迭代所有已添加的类型。因此,如果我理解正确,当添加对象时,您将返回其所有基本类型,并为每个类型保存导致此对象的驱动类型。然后,当请求类型时,您将使用缓存查找从m是请求的类型,并且添加了一个对象。这很好,但不处理接口,这是一个要求。问题是,如果我们开始迭代所有接口及其基本接口,它可能会变得有点疯狂…哦,是的,就像你说的那样。让我们假设这个层次结构
C:B:a
如果我添加了
C
,我就添加了它到
C
组,但保留一个C属于B和a的缓存。您也可以跳过此步骤(我的意思是,因为每个类型的继承树都不会更改)并且只做一次。对于接口,实际上没有任何变化。您可以应用我在这里发布的相同逻辑。您只需要更改几行即可。让我给您一个提示。您将从typeof(T).GetInterfaces()开始然后照样做loop@tbkn23,
问题是,如果我们开始迭代所有接口及其基本接口,它可能会变得有点疯狂…
← 这根本不是问题。正如我在评论中提到的,您所要做的就是留下一些关于哪个类型正在实现什么的面包屑interface@tbkn23,您能理解接口部分吗?:)是的,实现它不是问题。我关心的是,假设你添加了一个字典类型的对象。这意味着有几十个接口。但我想这不会太糟糕,因为我们在第一次添加某个类型的对象时只需要做一次,就像你说的链接不会改变。你能更新你的字典吗保证反映这两个更改,以便我可以接受它?(仅在第一次添加类型时留下面包屑,并包括接口)
var a = new A();
var b = new B();
var c = new C();
var objectholder = new Objectholder();
objectholder.AddObject(a);
objectholder.AddObject(b);
objectholder.AddObject(c);
// Contains A and B and C
var allA = objectholder.GetObjectsOf<A>().ToArray();