2

这是我的代码:

var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
    //some code
}

var props = type.GetProperties();
foreach (PropertyInfo prop in props)
{
    //exact same code
}

我知道我可以创建一个可以调用两次的函数,但我想做的(如果可能的话)是单个foreach. 像这样的东西(是的,代码不起作用。如果它起作用,我不会问这个问题!):

var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
var props = type.GetProperties();

foreach (PropertyInfo prop in fields && PropertyInfo prop in props)
{
    //some code
}

我真的觉得有办法,即使我知道我的解决方案远非可编译:(
感谢您的帮助!

4

6 回答 6

3

如果您对 MemberInfo 类(它是 FieldInfo 和 PropertyInfo 的基础)公开的属性没问题,那么您可以执行以下操作:

var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance).Cast<MemberInfo>();
var props = type.GetProperties().Cast<MemberInfo>();
var fieldsAndProperties = fields.Union(props);

foreach (MemberInfo mi in fieldsAndProperties)
{
...
}
于 2011-12-02T09:46:30.997 回答
1

如果在循环中公开的功能MemberInfo对您来说足够了,那么您可以在同一个数组或其他可枚举对象上连接字段和属性,并且只迭代一次。

这是可能的,因为两者都FieldInfo继承PropertyInfoMemberInfo类。

示例代码:

var fields = typeof(DateTime).GetFields(
    BindingFlags.Public | BindingFlags.Instance);

var properties = typeof(DateTime).GetProperties(
    BindingFlags.Public | BindingFlags.Instance);

var all = fields.Cast<MemberInfo>().Concat(properties.Cast<MemberInfo>());

foreach (MemberInfo mi in all)
{
    //some code
}
于 2011-12-02T09:45:57.953 回答
1

要将它们放入一个循环中:

foreach (MemberInfo member in fields.Cast<MemberInfo>().Concat(props))
{ 
    //I'm 100% sure this isn't what you want
    //because you need to set value here
    //in this case, you still need to check if member is a FieldInfo/PropertyInfo 
    //and then convert it before you set the values
}

实际上,在这里使用两个循环可能会更好。首先,代码看起来更清晰,因为它们在做不同的事情,一个设置字段值,另一个用于属性。其次,寄存器缓存可能有助于使您的程序比一个循环快一点。

于 2011-12-02T09:54:55.253 回答
0

嗯……

这种迭代正在失去字段和属性的顺序。例如

class Test
{
    public String tests { get; set; }
    public int    testi;
}

如果 GetFields 获得第一个 - 我们将“testi”作为第一个成员并通过 GetProperies 我们获得“测试”。Union 可能会合并它们,但不会保留顺序。

有没有办法获取字段和属性并保留它们的顺序?

于 2014-12-02T06:54:12.153 回答
0

我建议以下遍历一个对象并记录对象信息。

public static string ObjectToString(object obj)
{
    var sb = new StringBuilder();
    try
    {
        sb.AppendLine(obj.GetType().Name);
        foreach (var prop in obj.GetType().GetProperties())
        {
            sb.AppendLine(string.Format("{0} Property Name: {1}; Value: [{2}]; Type: {3}", "--->", prop.Name, prop.GetValue(obj, null)?.ToString(), prop.PropertyType?.FullName));
        }
        foreach (var fld in obj.GetType().GetFields())
        {
            if (!fld.FieldType.Namespace.Equals("System", StringComparison.InvariantCultureIgnoreCase) && fld.GetValue(obj) != null)
            {
                ObjectToString(fld.GetValue(obj), sb);
            }
            else
            {
                sb.AppendLine(string.Format("{0} Field Name: {1}; Value: [{2}]; Type: {3}", "--->", fld.Name, fld.GetValue(obj)?.ToString(), fld.FieldType?.FullName));
            }
        }
    }
    catch (Exception ex)
    {
        sb.AppendLine("---> Exception in ObjectToString: " + ex.Message);
    }
    return sb.ToString();
}
public static string ObjectToString(object obj, StringBuilder sb, int depth = 1)
{
    try
    {
        sb.AppendLine(string.Format("{0}{1} {2}", (depth==2?"----":""),"--->", obj.GetType().Name));
        foreach (var prop in obj.GetType().GetProperties())
        {
            sb.AppendLine(string.Format("{0} Property Name: {1}; Value: [{2}]; Type: {3}", "------->", prop.Name, prop.GetValue(obj, null)?.ToString(), prop.PropertyType?.FullName));
        }
        foreach (var fld in obj.GetType().GetFields())
        {
            //we want to avoid stake overflow and go only one more depth
            if (!fld.FieldType.Namespace.Equals("System", StringComparison.InvariantCultureIgnoreCase) && fld.GetValue(obj) != null && depth < 2)
            {
                ObjectToString(fld.GetValue(obj), sb, 2);
            }
            else
            {
                sb.AppendLine(string.Format("{0} Field Name: {1}; Value: [{2}]; Type: {3}", "------->", fld.Name, fld.GetValue(obj)?.ToString(), fld.FieldType?.FullName));
            }
        }

    }
    catch (Exception ex)
    {
        sb.AppendLine("-------> Exception in ObjectToString: depth(" + depth + ") " + ex.Message);
    }
    return sb.ToString();
}
于 2019-12-31T17:50:36.130 回答
0

使用反射访问成员属性的一个问题是它很慢。有一个小型库可以通过一些动态生成的访问器代码FastMember快速快速地完成这项工作。要使用它迭代所有公共字段和属性,您需要运行如下简单循环:

var ta = TypeAccessor.Create(typeof(MyClass));
foreach (var prop in ta.GetMembers())
{
    Console.WriteLine(prop.Name);

}

当您需要设置任何对象实例的字段或属性值时,可以这样做:

var instance = new MyClass();
ta[instance, prop.Name] = "myvalue";
于 2019-12-31T20:07:54.027 回答