循环GetFields和类型的GetProperties?

时间:2011-12-02 09:36:07

标签: c# foreach propertyinfo

这是我的代码:

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
}

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

6 个答案:

答案 0 :(得分: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)
{
...
}

答案 1 :(得分:1)

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

这是可能的,因为FieldInfoPropertyInfo都继承自MemberInfo类。

示例代码:

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
}

答案 2 :(得分: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
}

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

答案 3 :(得分:0)

嗯....嗯......

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

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

如果GetFields获得第一名 - 我们得到&#34; testi&#34;作为第一个成员,通过GetProperies我们得到&#34;测试&#34;。 联盟可能会将它们合并,但订单不会被保留。

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

答案 4 :(得分: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();
}

答案 5 :(得分:0)

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

string postData;
using (var stream = await request.Content.ReadAsStreamAsync())
{
    stream.Seek(0, SeekOrigin.Begin);
    using (var sr = new StreamReader(stream))
    {
        postData = await sr.ReadToEndAsync();
    }
}

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

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

}