【问题标题】:How to get all Guid properties and their values with the name "Id" from class?如何从类中获取名称为“Id”的所有 Guid 属性及其值?
【发布时间】:2021-12-09 08:28:12
【问题描述】:
我有一个包含嵌套对象的类。我想用名称“Id”获取所有 Guid 属性及其值。这是我的课程的简单版本:
public class Main
{
public Guid Id { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public Guid Id { get; set; }
public ICollection<GrandChild> GrandChildren { get; set; }
}
public class GrandChild
{
public Guid Id { get; set; }
}
我将拥有 Main 类对象,并想检索所有 Guid 属性及其所有嵌套等的值以进行进一步的逻辑。我需要使用反射。主类就是一个例子。我可以在运行时使用泛型类型。
有什么建议吗?
【问题讨论】:
标签:
c#
reflection
properties
ienumerable
【解决方案1】:
使用递归函数遍历层次结构。像这样的:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp34
{
public class Main
{
public Guid Id { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public Guid Id { get; set; }
public ICollection<GrandChild> GrandChildren { get; set; }
}
public class GrandChild
{
public Guid Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var main = new Main()
{
Children = new List<Child>()
{
new Child()
{
Id = Guid.NewGuid(),
GrandChildren = new List<GrandChild>()
{
new GrandChild() {Id=Guid.NewGuid() } ,
new GrandChild() {Id=Guid.NewGuid() } ,
new GrandChild() {Id=Guid.NewGuid() } ,
new GrandChild() {Id=Guid.NewGuid() }
}
},
new Child()
{
Id = Guid.NewGuid(),
GrandChildren = new List<GrandChild>()
{
new GrandChild() {Id=Guid.NewGuid() } ,
new GrandChild() {Id=Guid.NewGuid() } ,
new GrandChild() {Id=Guid.NewGuid() } ,
new GrandChild() {Id=Guid.NewGuid() }
}
}
}
};
foreach (var val in GetIds(main))
{
Console.WriteLine($"{val.Item1.GetType().Name} Id {val.Item2}");
}
}
internal static IEnumerable<(object,Guid)> GetIds(Object o)
{
var t = o.GetType();
foreach (var pId in t.GetProperties().Where( p => p.Name == "Id" && p.PropertyType == typeof(Guid)))
{
yield return (o, (Guid)pId.GetValue(o));
}
foreach (var pChild in t.GetProperties().Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)))
{
var children = (IEnumerable)pChild.GetValue(o);
foreach (var child in children)
{
foreach (var val in GetIds(child))
{
yield return val;
}
}
}
}
}
}
输出
Main Id 00000000-0000-0000-0000-000000000000
Child Id 971310cb-b1f6-4d27-91de-f1f4edcb1a3b
GrandChild Id 160ce573-e8bc-4cd6-9569-86d82e50d531
GrandChild Id 3524d68e-cbba-453f-a62c-b7530923f937
GrandChild Id 205ef5ac-c97c-45fc-b07a-aead02bd047e
GrandChild Id f79aff79-d3ef-46e0-a637-089bb4b8d9ec
Child Id dd789259-b1cb-4d12-b109-6318afbbc33f
GrandChild Id e909ef22-abf7-4aa7-bf07-8e82ea941203
GrandChild Id 16243269-1994-4d6e-b18e-1661c7e08867
GrandChild Id fba632c9-0450-4d42-86e6-b2b64479bc52
GrandChild Id 2ccb1f39-f046-41fe-b9db-68492c0d9010
【解决方案2】:
在这种情况下,我使用字典来定义如何查找后代。
但这可以通过搜索泛型类型直接完成。结果这个不使用匿名类型。
尽管如此,结果都是一样的,你必须递归遍历层次结构。
private static Dictionary<Type, Func<Type>> childTypeAccessor = new Dictionary<Type, Func<Type>>()
{
{ typeof(Main), () => typeof(Child) },
{ typeof(Child), () => typeof(GrandChild) }
};
public class TypeDef
{
public Type Type {get; set;}
public string PropertyName { get; set; }
}
private IEnumerable<TypeDef> SearchTypeProperties(Type type, Type searchType)
{
var properties = type.GetProperties().Where(p => p.PropertyType == searchType).Select(p =>
new TypeDef { Type = type, PropertyName = p.Name }
);
if (childTypeAccessor.ContainsKey(type))
{
var subproperties = SearchTypeProperties(childTypeAccessor[type](), searchType);
return properties.Concat(subproperties).ToList();
}
return properties.ToList();
}