8

我写了一个接受泛型参数的方法,然后打印它的属性。我用它来测试我的网络服务。它正在工作,但我想添加一些我不知道如何实现的功能。我想打印列表的值,因为现在它只写 System.Collection.Generic.List1 这是预期的。

到目前为止,这是我的代码,这适用于基本类型(int、double 等):

static void printReturnedProperties<T>(T Object)
{ 
   PropertyInfo[] propertyInfos = null;
   propertyInfos = Object.GetType().GetProperties();

   foreach (var item in propertyInfos)
      Console.WriteLine(item.Name + ": " + item.GetValue(Object).ToString());
}
4

6 回答 6

9

你可以这样做:

    static void printReturnedProperties(Object o)
    {
        PropertyInfo[] propertyInfos = null;
        propertyInfos = o.GetType().GetProperties();



        foreach (var item in propertyInfos)
        {
            var prop = item.GetValue(o);

            if(prop == null)
            {
                Console.WriteLine(item.Name + ": NULL");
            }
            else
            {
                Console.WriteLine(item.Name + ": " + prop.ToString());
            }


            if (prop is IEnumerable)
            {
                foreach (var listitem in prop as IEnumerable)
                {
                    Console.WriteLine("Item: " + listitem.ToString());
                }
            }
        }


    }

然后它将枚举任何 IEnumerable 并打印出各个值(我每行打印一个,但显然,您可以做不同的事情。)

于 2013-03-05T21:32:29.110 回答
4

可以通过 indexer 属性检索列表中的元素Item。这个属性接受一个索引参数(有一个PropertyInfo.GetValue接受object数组的重载,就像MethodInfo.Invoke)并返回那个位置的对象。

int index = /* the index you want to get here */;
PropertyInfo indexer = Object.GetProperty("Item");
object item = indexer.GetValue(Object, new object[] { index });
于 2013-03-05T21:17:23.870 回答
2

,我通常在每个项目之间打印一个列表。

为了方便起见,我创建了一个简单的扩展方法:

public static class ListEx
{
    public static string StringJoin<T>(this IEnumerable<T> items)
    {
        return string.Join(", ", items);
    }
}

将该方法称为myList.StringJoin().

您当然可以修改方法以string.Join直接使用另一个分隔符 och 调用。

于 2013-03-05T21:18:48.537 回答
1

这是一个片段,假设您的 List 是 T 型。

 foreach (PropertyInfo item in propertyInfos)
            {
                Object obj = item.GetValue(object,null);
                if (!obj.GetType().IsValueType)
                {
                    if (obj.GetType() == typeof(String))
                    {
                        Console.WriteLine(obj.ToString());
                    }
                    else if (obj.GetType() == typeof(List<T>))
                    {
                        //run a loop and print the list

                    }
                    else if (obj.GetType().IsArray) // this means its Array
                    {
                        //run a loop to print the array
                    }

                }
                else
                {
                    //its primitive so we will convert to string 
                    Console.WriteLine(obj.ToString());

                }
于 2013-03-05T21:32:31.180 回答
1

我想你想要这样的东西:

public class Program
{
    public static void PrintProperties<T>(T t)
    {
        var properties = t.GetType().GetProperties();

        foreach (var property in properties)
        {
            var name = property.Name;
            var value = property.GetValue(t, null);

            if (property.PropertyType.IsGenericType && property.PropertyType == typeof(IEnumerable<>))
            {
                var formatList = typeof(Program).GetMethod("FormatList", new[] { value.GetType() });

                // value.GetType().GetGenericArguments().First() will get you the underlying type of the list,
                // i.e., the TItemType where the property you are currently
                // handling is of type IEnumerable<TItemType>
                formatList.MakeGenericMethod(value.GetType().GetGenericArguments().First());

                value = formatList.Invoke(null, new object[] { value });

                Console.Out.WriteLine(name + ": " + value);
            }
            else
            {
                Console.Out.WriteLine(name + ": " + value);
            }
        }
    }

    public static string FormatList<TPlaceholder>(IEnumerable<TPlaceholder> l)
    {
        return string.Join(", ", l);
    }
}

该代码未经测试,但基本上,与标量值相比,您希望以不同的方式处理可枚举类型,因此一旦您遇到 type 的某些内容IEnumerable<TItemType>,您就可以调用该FormatList<TPlaceholder>方法。

现在,请记住,您的原始TTItemType不一定相同。当您使用反射调用 FormatList 时,您希望将其绑定TPlaceholderTItemType. 完成后,您只需调用格式化方法并将列表的实际实例传递给它,它会返回一个字符串。然后你可以输出那个字符串。

希望有帮助。

于 2013-03-05T21:40:51.293 回答
0

大量借鉴上述示例,这是我的完整解决方案。这已经过测试并通过打印出每个元素的属性来处理传入的 IEnumerable。它不是递归的,但很容易添加。

请注意,上述许多示例都会因索引属性(例如列表)而崩溃。 property.GetValue() 中的参数计数不匹配

通过使用这一位 LINQ 过滤具有索引属性的属性,可以避免这种情况。

Where(x=>!x.GetIndexParameters().Any())

下面是扩展方法形式的完整示例。

    /// <summary>
    /// Returns string representation of object property states i.e. Name: Jim, Age: 43
    /// </summary>
    public static string GetPropertyStateList(this object obj)
    {
        if (obj == null) return "Object null";

        var sb = new StringBuilder();
        var enumerable = obj as IEnumerable;

        if (enumerable != null)
        {
            foreach (var listitem in enumerable)
            {
                sb.AppendLine();
                sb.Append(ReadProperties(listitem));
            }
        }
        else
        {
            sb.Append(ReadProperties(obj));
        }

        return sb.ToString();
    }

    private static string ReadProperties(object obj)
    {
        var sb = new StringBuilder();
        var propertyInfos = obj.GetType().GetProperties().OrderBy(x => x.Name).Where(x=>!x.GetIndexParameters().Any());

        foreach (var prop in propertyInfos)
        {
            var value = prop.GetValue(obj, null) ?? "(null)";
            sb.AppendLine(prop.Name + ": " + value);
        }

        return sb.ToString();
    }
于 2017-04-06T18:04:09.853 回答