C#反射:获取类和基类的所有成员的信息

C#反射:获取类和基类的所有成员的信息,c#,reflection,C#,Reflection,当我运行下面的代码时,它只返回一个MethodInfo/FieldInfo/等,它直接属于我在其中搜索信息对象的类型。不管信息对象驻留在基类中并且可能是私有的,我如何找到它? 如果在子类中找不到info对象,下面的代码将检查对象的每个基类。请注意,尽管它将返回基类信息对象,但它将返回它“首先运行到”的对象,因此,如果您的子类中有一个名为_blah的变量,并且基类中有一个名为_blah的变量,则将返回子类中的_blah public static MethodInfo GetMethodInfo

当我运行下面的代码时,它只返回一个
MethodInfo
/
FieldInfo
/等,它直接属于我在其中搜索信息对象的
类型。不管信息对象驻留在基类中并且可能是私有的,我如何找到它?


如果在子类中找不到info对象,下面的代码将检查对象的每个基类。请注意,尽管它将返回基类信息对象,但它将返回它“首先运行到”的对象,因此,如果您的子类中有一个名为
_blah
的变量,并且基类中有一个名为
_blah
的变量,则将返回子类中的
_blah

public static MethodInfo GetMethodInfo(this Type objType, string methodName, BindingFlags flags, bool isFirstTypeChecked = true)
{
    MethodInfo methodInfo = objType.GetMethod(methodName, flags);
    if (methodInfo == null && objType.BaseType != null)
    {
        methodInfo = objType.BaseType.GetMethodInfo(methodName, flags, false);
    }
    if (methodInfo == null && isFirstTypeChecked)
    {
        throw new MissingMethodException(String.Format("Method {0}.{1} could not be found with the following BindingFlags: {2}", objType.ReflectedType.FullName, methodName, flags.ToString()));
    }
    return methodInfo;
}

public static FieldInfo GetFieldInfo(this Type objType, string fieldName, BindingFlags flags, bool isFirstTypeChecked = true)
{
    FieldInfo fieldInfo = objType.GetField(fieldName, flags);
    if (fieldInfo == null && objType.BaseType != null)
    {
        fieldInfo = objType.BaseType.GetFieldInfo(fieldName, flags, false);
    }
    if (fieldInfo == null && isFirstTypeChecked)
    {
        throw new MissingFieldException(String.Format("Field {0}.{1} could not be found with the following BindingFlags: {2}", objType.ReflectedType.FullName, fieldName, flags.ToString()));
    }
    return fieldInfo;
}

嗯,您回答了自己的问题,但据我所知,您的主要需求是
如何查找信息对象,而不管它在层次结构中的位置如何?

这里不需要递归来获取完整层次结构中的所有成员。您可以在
类型上使用
GetMembers
函数,它将返回所有成员,包括所有基类

下一个代码示例演示了这一点:

var names = 
    typeof(MyClass).GetMembers()
                   .Select (x => x.Name);

Console.WriteLine (string.Join(Environment.NewLine, names));
对于这样的结构

class MyClass : Base
{
    public string Name { get; set; }
    public string Surname { get; set; }
}

class Base
{
    public string Name { get; set; }
}
返回

get_Name
set_Name
get_Surname
set_Surname
get_Name
set_Name
ToString
Equals
GetHashCode
GetType
.ctor
Name
Surname

请注意,
get\u Name
auto属性的访问器出现两次,因为
MyClass
隐藏了基类的
Name
属性。还要注意
ToString
GetType
object
class

中定义的其他方法,我修改了bsara的实现,以便能够找到私有成员

我是这样使用它的:

public static void Save(string filename, object obj)
{
    try
    {
        using Stream s = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None);
        var b = new BinaryFormatter();
        b.Serialize(s, obj);
    }
    catch(SerializationException e)
    {
        var type= e.Message.Split("in Assembly")[0].Replace("Type", string.Empty).Replace("'", string.Empty).Trim();
        var assembly=e.Message.Split("in Assembly")[1].Split("'")[1];
        var atype= Type.GetType(type);

        string path = FindObject(new Stack<object>(new object[] { obj }), atype, "[myself]");

        throw new SerializationException($"Could not serialize path {path} in {obj.GetType().Name} due to not being able to process {type} from {assembly}. see inner exception for details", e);
    }            
}
publicstaticvoidsave(字符串文件名,objectobj)
{
尝试
{
使用streams=newfilestream(文件名,FileMode.Create,FileAccess.Write,FileShare.None);
var b=新的二进制格式化程序();
b、 序列化(s,obj);
}
捕获(序列化异常)
{
var type=e.Message.Split(“在程序集中”)[0]。替换(“type”,string.Empty)。替换(“”,string.Empty)。Trim();
var assembly=e.Message.Split(“在程序集中”)[1]。Split(“”)[1];
var atype=Type.GetType(Type);
字符串path=FindObject(新堆栈(新对象[]{obj}),类型为“[imf]”;
抛出新的SerializationException($“无法序列化{obj.GetType().Name}中的路径{path},因为无法从{assembly}处理{type}。有关详细信息,请参阅内部异常”,e);
}            
}
有一个小更新的方法:

private static bool TrySerialize(object obj)
{
    if(obj == null)
        return true;
    var stream = new MemoryStream();
    var bf = new BinaryFormatter();
    try
    {
        bf.Serialize(stream, obj);
    }
    catch(SerializationException)
    {
        return false;
    }
    return true;
}
private static string FindObject(Stack<object> self, Type typeToFind, string path)
{
    var _self = self.Peek();
    if(self.Where(x => x.Equals(_self)).Count() > 1) return null;
    foreach(var prop in _self.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic).Where(x => !x.GetCustomAttributes(true).Any(y => y is XmlIgnoreAttribute)))
    {
        switch(prop.MemberType)
        {
            case System.Reflection.MemberTypes.Property:
                {
                    var line = string.Format("{0}::{1}", path, prop.Name);
                    var _prop = prop as PropertyInfo;

                    if(_prop.GetIndexParameters().Count() > 0) break;

                    if(typeToFind.IsAssignableFrom(_prop.PropertyType))
                        return line;


                    if(_prop.PropertyType.IsPrimitive || _prop.PropertyType == typeof(DateTime) || _prop.PropertyType == typeof(string))
                        continue;

                    var subInst = _prop.GetValue(_self, new object[0]);
                    if(subInst == null)
                        continue;

                    if(!TrySerialize(subInst))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize {0}\n", line));
                    }

                    self.Push(subInst);
                    var result = FindObject(self, typeToFind, line);
                    self.Pop();
                    if(result != null)
                        return result;
                }
                break;
            case System.Reflection.MemberTypes.Field:
                {
                    var line = string.Format("{0}::*{1}", path, prop.Name);
                    var _prop = prop as FieldInfo;

                    if(typeToFind.IsAssignableFrom(_prop.FieldType))
                        return line;

                    if(_prop.FieldType.IsPrimitive || _prop.FieldType == typeof(DateTime) || _prop.FieldType == typeof(string))
                        continue;

                    var subInst = _prop.GetValue(_self);
                    if(subInst == null)
                        continue;

                    if(!TrySerialize(subInst))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize field {0}\n", line));
                    }

                    self.Push(subInst);
                    var result = FindObject(self, typeToFind, line);
                    self.Pop();
                    if(result != null)
                        return result;
                }
                break;

            case System.Reflection.MemberTypes.Event:
                {
                    var line = string.Format("{0}::!{1}", path, prop.Name);
                    var _prop = prop as EventInfo;


                    if(typeToFind.IsAssignableFrom(_prop.EventHandlerType))
                        return line;

                    var field =  _self.GetType().GetField(_prop.Name,
                BindingFlags.NonPublic |BindingFlags.Instance |BindingFlags.GetField);


                    if(field != null && !field.GetCustomAttributes(true).Any(x => x is NonSerializedAttribute)  && !TrySerialize(field.GetValue(_self)))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize event {0}\n", line));
                    }


                }
                break;

            case System.Reflection.MemberTypes.Custom:
                {

                }
                break;
            default: break;
        }


    }
    if(_self is IEnumerable)
    {
        var list = (_self as IEnumerable).Cast<object>();
        var index = 0;
        foreach(var item in list)
        {
            index++;
            self.Push(item);
            var result = FindObject(self, typeToFind, string.Format("{0}[{1}]", path, index));
            self.Pop();
            if(result != null)
                return result;
        }
    }

    return null;
}
private static bool TrySerialize(对象对象对象)
{
if(obj==null)
返回true;
var stream=newmemoryStream();
var bf=新的二进制格式化程序();
尝试
{
序列化(流,对象);
}
捕获(序列化异常)
{
返回false;
}
返回true;
}
私有静态字符串FindObject(堆栈自身,类型typeToFind,字符串路径)
{
var_self=self.Peek();
if(self.Where(x=>x.Equals(_self)).Count()>1)返回null;
foreach(在_self.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)中使用var prop,其中(x=>!x.GetCustomAttributes(true).Any(y=>y是XmlIgnoreAttribute)))
{
开关(属性成员类型)
{
案例System.Reflection.MemberTypes.Property:
{
var line=string.Format(“{0}::{1}”,路径,属性名);
var_prop=prop作为PropertyInfo;
如果(_prop.GetIndexParameters().Count()>0)中断;
if(类型查找可从(_prop.PropertyType))中指定)
回流线;
if(_prop.PropertyType.IsPrimitive | | |(u prop.PropertyType==typeof(DateTime)| |(u prop.PropertyType==typeof(string))
继续;
var subInst=_prop.GetValue(_self,新对象[0]);
if(subInst==null)
继续;
如果(!TrySerialize(subInst))
{
System.Diagnostics.Debugger.Log(0,”,string.Format(“无法序列化{0}\n”,第行));
}
自推(subInst);
var结果=FindObject(self、typeToFind、line);
self.Pop();
如果(结果!=null)
返回结果;
}
打破
案例System.Reflection.MemberTypes.Field:
{
var line=string.Format(“{0}::*{1}”,路径,prop.Name);
var _prop=作为字段信息的属性;
if(类型查找可从(_prop.FieldType))中指定)
回流线;
if(_prop.FieldType.IsPrimitive | | | u prop.FieldType==typeof(DateTime)| | u prop.FieldType==typeof(string))
继续;
var subInst=_prop.GetValue(_self);
if(subInst==null)
继续;
如果(!TrySerialize(subInst))
{
System.Diagnostics.Debugger.Log(0,”,string.Format(“无法序列化字段{0}\n”,第行));
}
自推(subInst);
var结果=FindObject(self、typeToFind、line);
self.Pop();
如果(结果!=null)
返回结果;
}
打破
案例System.Reflection.MemberTypes.Event:
{
var line=string.Format(“{0}::!{1}”,路径,属性名);
var_prop=prop作为事件信息;
if(type-tofind.IsAssignableFrom(_prop.EventHandlerType))
回流线;
var field=\u self.GetType().GetField(\u prop.Name,
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField);
如果(字段!=null&&!f
private static bool TrySerialize(object obj)
{
    if(obj == null)
        return true;
    var stream = new MemoryStream();
    var bf = new BinaryFormatter();
    try
    {
        bf.Serialize(stream, obj);
    }
    catch(SerializationException)
    {
        return false;
    }
    return true;
}
private static string FindObject(Stack<object> self, Type typeToFind, string path)
{
    var _self = self.Peek();
    if(self.Where(x => x.Equals(_self)).Count() > 1) return null;
    foreach(var prop in _self.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic).Where(x => !x.GetCustomAttributes(true).Any(y => y is XmlIgnoreAttribute)))
    {
        switch(prop.MemberType)
        {
            case System.Reflection.MemberTypes.Property:
                {
                    var line = string.Format("{0}::{1}", path, prop.Name);
                    var _prop = prop as PropertyInfo;

                    if(_prop.GetIndexParameters().Count() > 0) break;

                    if(typeToFind.IsAssignableFrom(_prop.PropertyType))
                        return line;


                    if(_prop.PropertyType.IsPrimitive || _prop.PropertyType == typeof(DateTime) || _prop.PropertyType == typeof(string))
                        continue;

                    var subInst = _prop.GetValue(_self, new object[0]);
                    if(subInst == null)
                        continue;

                    if(!TrySerialize(subInst))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize {0}\n", line));
                    }

                    self.Push(subInst);
                    var result = FindObject(self, typeToFind, line);
                    self.Pop();
                    if(result != null)
                        return result;
                }
                break;
            case System.Reflection.MemberTypes.Field:
                {
                    var line = string.Format("{0}::*{1}", path, prop.Name);
                    var _prop = prop as FieldInfo;

                    if(typeToFind.IsAssignableFrom(_prop.FieldType))
                        return line;

                    if(_prop.FieldType.IsPrimitive || _prop.FieldType == typeof(DateTime) || _prop.FieldType == typeof(string))
                        continue;

                    var subInst = _prop.GetValue(_self);
                    if(subInst == null)
                        continue;

                    if(!TrySerialize(subInst))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize field {0}\n", line));
                    }

                    self.Push(subInst);
                    var result = FindObject(self, typeToFind, line);
                    self.Pop();
                    if(result != null)
                        return result;
                }
                break;

            case System.Reflection.MemberTypes.Event:
                {
                    var line = string.Format("{0}::!{1}", path, prop.Name);
                    var _prop = prop as EventInfo;


                    if(typeToFind.IsAssignableFrom(_prop.EventHandlerType))
                        return line;

                    var field =  _self.GetType().GetField(_prop.Name,
                BindingFlags.NonPublic |BindingFlags.Instance |BindingFlags.GetField);


                    if(field != null && !field.GetCustomAttributes(true).Any(x => x is NonSerializedAttribute)  && !TrySerialize(field.GetValue(_self)))
                    {
                        System.Diagnostics.Debugger.Log(0, "", string.Format("Cannot serialize event {0}\n", line));
                    }


                }
                break;

            case System.Reflection.MemberTypes.Custom:
                {

                }
                break;
            default: break;
        }


    }
    if(_self is IEnumerable)
    {
        var list = (_self as IEnumerable).Cast<object>();
        var index = 0;
        foreach(var item in list)
        {
            index++;
            self.Push(item);
            var result = FindObject(self, typeToFind, string.Format("{0}[{1}]", path, index));
            self.Pop();
            if(result != null)
                return result;
        }
    }

    return null;
}