如何在不遍历属性的情况下将类的实例表示为字符串
本文关键字:实例 表示 字符串 情况下 遍历 属性 | 更新日期: 2023-09-27 18:24:11
出于调试目的,我需要打印某些类实例的所有公共字段/属性。我能自动做到吗?.NET 4.0中可能有新功能?例如,WPF DataGrid可以做类似的事情。
这可以手动引用这个问题,遍历类字段并打印它们,但如果我可以使用一些库方法而不是自己编码,我会很感兴趣吗?
即,我想替换这个代码:
foreach (PropertyInfo prop in typeof(ServerInfo).GetProperties())
{
result += prop.Name + " = " + prop.GetValue(si, null) + "'n";
}
foreach (FieldInfo prop in typeof(ServerInfo).GetFields())
{
result += prop.Name + " = " + prop.GetValue(si) + "'n";
}
return result;
我不知道您为什么要寻找更好的代码。你的代码只有几行,对我来说很好。
如果你想修改任何类型的代码,那么很简单:
string Format(object obj)
{
Type type = obj.GetType();
foreach (PropertyInfo prop in type.GetProperties())
{
result += prop.Name + " = " + prop.GetValue(obj, null) + "'n";
}
foreach (FieldInfo field in type.GetFields())
{
result += field.Name + " = " + field.GetValue(obj) + "'n";
}
return result;
}
在这段代码中,另一个可以做得更好的地方是效率:应该使用StringBuilder
而不是串联字符串。
您可以覆盖自定义类的ToString
方法,并使用如下所述的方法:https://stackoverflow.com/a/6745255/559144
或者创建自己的库/助手,将代码放在链接上,对于所有要使用的类,只需从ToString
重写中调用助手方法即可。
不确定你所说的WPF Datagrid是什么意思。你确定你说的不是Visual Studio调试器数据集可视化工具吗?
引自Thomas:
User user = ...
foreach(PropertyInfo prop in typeof(User).GetProperties())
{
Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(user, null));
}
如果您的目标是用WPF显示一个简单的属性列表,那么对对象使用带有ItemsSource"DataBound"的ListBox可能会有所帮助。为了从该对象中获得作为字符串的属性列表,请使用IValueConverter的一些实现,该实现读取最后几条注释中描述的属性,并将它们放入IEnumerable中。
在DataBinding中交换对象时,会立即显示新对象。
如果您真的对所有属性和字段都进行了设置,那么没有比您已经编写的代码更好的方法了。您可以编写一个扩展方法并将其合并到System命名空间中,这样它就会出现在任何类型的每个实例上;我也会认真考虑使用StringBuilder
、AppendLine
和string.Format
:
namespace System
{
public static class MyExtensions
{
public static string Report<T>(this T instance)
{
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo prop in typeof(T).GetProperties())
{
sb.AppendLine(
string.Format("{0} = {1}", prop.Name, prop.GetValue(si, null));
}
foreach (FieldInfo prop in typeof(T).GetFields())
{
sb.AppendLine(
string.Format("{0} = {1}", prop.Name, prop.GetValue(si, null));
}
return sb.ToString();
}
}
}
一旦你写了这篇文章,你可以简单地做:
var instance = new ServerInfo();
var report = instance.Report();
这样做的问题是,它无法处理类型的最佳表示实际上只是"ToString"调用的情况,例如int
或string
(尤其是字符串;因为此代码只会输出Length
成员)。
您提到了WPF数据网格——值得一提的是,它不直接使用反射,而是使用System.ComponentModel.TypeDescriptor
类——它是可扩展的,并使用TypeConverter
机制来支持到字符串的转换(比简单地依赖ToString
要好得多)。
但是,它在生成的元数据中不包括字段;这显然是你想要的。
最后,我认为这种东西不应该在程序中大量使用;因为这种程度的细节很少真正重要。然后是你的报告应该深入到什么程度的问题;对于每个成员,您实际上是否应该不再使用Report
(在这种情况下,您必须延迟绑定泛型,或者只编写它以使用object
)?但是,您有一些讨厌的代码来检查应该降为或仅为ToString
'd的类型。如果你开始这样做,你也需要注意不要通过交叉引用重复出现;否则,您的报告方法可能会锁定您的应用程序。
相反,我建议接口是最好的:
public interface IReportable
{
void Report(StringBuilder target);
}
然后,接口的实现仅限于您真正需要报告的类型;您可以使用上面的扩展方法或类似的方法,作为大多数类型的默认实现。然而,至关重要的是,如果需要,一个类型可以提供自己的。
您可以为Type
类编写扩展方法:
public static class TypeExtensions
{
public static List<string> GetFieldsAndPropertiesAsString(this Type type)
{
return new List<string>(type.GetFieldsAsString().Union(type.GetPropertiesAsString()));
}
public static IEnumerable<string> GetFieldsAsString(this Type type)
{
// Modify BindingFlags to get what you want (instance only, private/public...)
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
{
yield return field.Name;
}
}
public static IEnumerable<string> GetPropertiesAsString(this Type type)
{
// Modify BindingFlags to get what you want (instance only, private/public...)
foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
yield return prop.Name;
}
}
}
然后使用进行调用
foreach (string zz in typeof(MyClass).GetFieldsAndPropertiesAsString())
{
Console.WriteLine(zz);
}