我有一个方法,它解析xml并从该xml创建指定类型的对象。这一切都是使用泛型完成的,以便为所有类型提供一个通用方法。
我的问题是,我想使用类型名称(而不是名称)在各种类中搜索属性。假设属性有一个类型"type1",那么一些类定义声明如下:
class foo1
{
type1 prop1{get;set;}
}
class foo2
{
foo1 prop2{get;set;}
}
class foo3:foo2
{
type2 prop3{get;set;}
}
对于上面声明的所有类,如果我创建对象,那么我想访问上面所述类的每个实例的type1
类型的属性,即我应该能够从foo1
、foo2
、foo3
类的对象中获得声明为type1
的属性的值。我真的想要一种通用的方法来做这件事,因为类可能会增加。
这里有一种方法可以让几乎做到这一点。缺少的是使用反射BindingFlags.FlattenHierarchy不会返回父类的私有方法。将这些类型标记为受保护类型或公共类型将解决此问题。(您也可以手动遍历基类来读取私有成员。)
如果你想在程序集中找到声明给定类型属性的所有类型,你可以写一个方法,比如:
// using System.Reflection
public IEnumerable<Type> GetTypesWithPropertyOfType(Assembly a, Type t)
{
BindingFlags propertyBindingFlags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.FlattenHierarchy;
// a property is kept if it is assignable from the type
// parameter passed in
MemberFilter mf = (pi, crit)=>
(pi as PropertyInfo)
.PropertyType
.IsAssignableFrom(t);
// a class is kept if it contains at least one property that
// passes the property filter. All public and nonpublic properties of
// the class, and public and protected properties of the base class,
// are considered
Func<Type, bool> ClassFilter =
c=>c.FindMembers(MemberTypes.Property, propertyBindingFlags, mf, null)
.FirstOrDefault() != null;
// return all classes in the assembly that match ClassFilter
return
a.GetTypes()
.Where(c=>c.IsClass)
.Where(ClassFilter);
}
要在执行程序集中查找定义或继承type1
类型属性的类,可以调用:
var v = GetTypesWithPropertyOfType(
Assembly.GetExecutingAssembly(),
typeof(type1));
foreach (var n in v) Console.WriteLine(n.FullName);
这会打印出foo1。如果定义foo类的代码被修改为(a)使foo1.prop1
公开或受保护,以及(b)使foo2
从foo1
继承,那么上面的代码将打印:
foo1
foo2
foo3
正如预期的那样。