我通常会覆盖ToString()方法以输出属性名称和与之关联的值。我有点厌倦手工编写这些,所以我正在寻找一个动态的解决方案。
主:
TestingClass tc = new TestingClass()
{
Prop1 = "blah1",
Prop2 = "blah2"
};
Console.WriteLine(tc.ToString());
Console.ReadLine();
TestingClass:
public class TestingClass
{
public string Prop1 { get; set; }//properties
public string Prop2 { get; set; }
public void Method1(string a) { }//method
public TestingClass() { }//const
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (Type type in System.Reflection.Assembly.GetExecutingAssembly().GetTypes())
{
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
sb.Append(property.Name);
sb.Append(": ");
sb.Append(this.GetType().GetProperty(property.Name).Name);
sb.Append(System.Environment.NewLine);
}
}
return sb.ToString();
}
}
目前输出:
Prop1: System.String Prop1
Prop2: System.String Prop2
期望的输出:
Prop1: blah1
Prop2: blah2
我对其他解决方案持开放态度,它不必使用反射,它只需要产生所需的输出。
答案 0 :(得分:18)
这对我有用:
public class TestingClass
{
public string Prop1 { get; set; }//properties
public string Prop2 { get; set; }
public void Method1(string a) { }//method
public TestingClass() { }//const
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (System.Reflection.PropertyInfo property in this.GetType().GetProperties())
{
sb.Append(property.Name);
sb.Append(": ");
if (property.GetIndexParameters().Length > 0)
{
sb.Append("Indexed Property cannot be used");
}
else
{
sb.Append(property.GetValue(this, null));
}
sb.Append(System.Environment.NewLine);
}
return sb.ToString();
}
}
要使其在任何地方都可用,您可以创建扩展程序 无法覆盖扩展中的方法,但它仍然可以简化您的生活。
public static class MyExtensions
{
public static string ToStringExtension(this object obj)
{
StringBuilder sb = new StringBuilder();
foreach (System.Reflection.PropertyInfo property in obj.GetType().GetProperties())
{
sb.Append(property.Name);
sb.Append(": ");
if (property.GetIndexParameters().Length > 0)
{
sb.Append("Indexed Property cannot be used");
}
else
{
sb.Append(property.GetValue(obj, null));
}
sb.Append(System.Environment.NewLine);
}
return sb.ToString();
}
}
然后,您可以在每个对象上调用ToStringExtension()
缺点是,它对列表等不起作用,例如:
var list = new List<string>();
// (filling list ommitted)
list.ToStringExtension();
// output:
// Capacity: 16
// Count: 11
// Item: Indexed Property cannot be used
答案 1 :(得分:4)
这是一个扩展,它将报告标准类型,如string,int和Datetime,但也会报告字符串列表(如下面AccessPoints
所示,上面的答案无法处理)。请注意,输出对齐如下:
Name : Omegaman
ID : 1
Role : Admin
AccessPoints : Alpha, Beta, Gamma
WeekDays : Mon, Tue
StartDate : 3/18/2014 12:16:07 PM
以下是任何类型的扩展,只要它是一个类。然后它反映了公共和私人财产,如果它们不是空报告它们。
public static string ReportAllProperties<T>(this T instance) where T : class
{
if (instance == null)
return string.Empty;
var strListType = typeof(List<string>);
var strArrType = typeof(string[]);
var arrayTypes = new[] { strListType, strArrType };
var handledTypes = new[] { typeof(Int32), typeof(String), typeof(bool), typeof(DateTime), typeof(double), typeof(decimal), strListType, strArrType };
var validProperties = instance.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(prop => handledTypes.Contains(prop.PropertyType))
.Where(prop => prop.GetValue(instance, null) != null)
.ToList();
var format = string.Format("{{0,-{0}}} : myInstance.ReportAllProperties()
", validProperties.Max(prp => prp.Name.Length));
return string.Join(
Environment.NewLine,
validProperties.Select(prop => string.Format(format,
prop.Name,
(arrayTypes.Contains(prop.PropertyType) ? string.Join(", ", (IEnumerable<string>)prop.GetValue(instance, null))
: prop.GetValue(instance, null)))));
}
{{1}}
请注意,这是基于我的博客文章C#: ToString To Report all Properties Even Private Ones Via Reflection,该文章提供了对正在发生的事情的更有力的解释。
答案 2 :(得分:0)
这是我发现的,适用于大多数复杂类型(包括List):
public static string ToXml(object Obj, System.Type ObjType)
{
try
{
XmlSerializer ser;
XmlSerializerNamespaces SerializeObject = new mlSerializerNamespaces();
ser = new XmlSerializer((ObjType));
MemoryStream memStream;
memStream = new MemoryStream();
XmlTextWriter xmlWriter;
xmlWriter = new XmlTextWriter(memStream, Encoding.UTF8);
xmlWriter.Namespaces = true;
XmlQualifiedName[] qualiArrayXML = SerializeObject.ToArray();
ser.Serialize(xmlWriter, Obj);
xmlWriter.Close();
memStream.Close();
string xml;
xml = Encoding.UTF8.GetString(memStream.GetBuffer());
xml = xml.Substring(xml.IndexOf(Convert.ToChar(60)));
xml = xml.Substring(0, (xml.LastIndexOf(Convert.ToChar(62)) + 1));
return xml;
}
catch (Exception ex)
{ return string.Empty; }
}
用法:
string classAasString = ClassToXml.ToXml(a, typeof(ClassA)); //whare ClassA is an object
答案 3 :(得分:0)
我自己遇到了这个问题,我在这里寻找一个序列化为可读性的选项。如果没有只读属性,则xml序列化可以提供可读的字符串。但是,如果存在只读属性/字段,则不能选择xml序列化。
public static string ToString(object serializeable)
{
var type = serializeable.GetType();
try
{
var sw = new StringWriter();
new XmlSerializer(type).Serialize(sw, serializeable);
return sw.ToString();
}
catch
{
return type.FullName;
}
}
答案 4 :(得分:0)
所以我写了一个扩展方法,该方法调用了一个已经弄清所有巫毒的库。
“覆盖字符串ToString()”与(我)“ ToStringDump” ....
在显示代码之前,我喜欢扩展方法(在这种情况下为ToStringDump)的原因。更好的原因是,我不必将POCO / DTO对象与ObjectDump引用混淆。我认为POCO和DTO应该“非常干净”,甚至应该隔离在自己的组件中。这样,这些poco / dto对象就可以轻松共享。
public static class ObjectDumpAdapter
{
public static string ToStringDump(this object obj)
{
string returnValue = ObjectDumper.Dump(obj);
return returnValue;
}
}
我的dotnet核心csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ObjectDumper.NET" Version="2.5.20033.1" />
</ItemGroup>
</Project>
Nuget链接:
https://www.nuget.org/packages/ObjectDumper.NET/
报价:
ObjectDumper是一个实用程序,旨在将C#对象序列化为字符串 用于调试和记录。
(来自https://nugetmusthaves.com/Package/ObjectDumper.NET)
GitHub链接:
答案 5 :(得分:0)
我将使用JSON,序列化器将为您完成所有艰苦的工作:
public static class ObjectExtensions
{
public static string ToStringEx(this object obj)
{
return JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true });
}
}