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