使用反射动态重写 ToString()

发布于 2025-01-06 02:48:22 字数 1257 浏览 0 评论 0原文

我通常重写 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

我愿意接受其他解决方案,它不必使用反射,它只需产生所需的输出。

I generally override the ToString() method to output the property names and the values associated to them. I got a bit tired of writing these by hand so I'm looking for a dynamic solution.

Main:

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();
    }
}

This currently outputs:

Prop1: System.String Prop1
Prop2: System.String Prop2

Desired Output:

Prop1: blah1
Prop2: blah2

I'm open for other solutions, it doesn't have to use reflection, it just has to produce the desired output.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

晨曦慕雪 2025-01-13 02:48:22

这对我有用:

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

This works for me:

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();
    }
}

To make it available everywhere you can create an Extension.
It's not possible to override methods in an Extension, but still it should simplify your life.

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();
    }
}

You can then call ToStringExtension() on every object.
Downside is, it doesn't work perfectly for lists etc., example:

var list = new List<string>();
// (filling list ommitted)
list.ToStringExtension();
// output:
// Capacity: 16
// Count: 11
// Item: Indexed Property cannot be used
绝不放开 2025-01-13 02:48:22

这是一个扩展,它将报告标准类型,例如 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}}} : {{1}}", 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)))));
}

用法

myInstance.ReportAllProperties()

请注意,这是基于我的博客文章 C#: ToString To通过反射报告所有属性,甚至是私有属性,这对正在发生的事情提供了更可靠的解释。

Here is an extension which will report the standard types such as string, int and Datetime but will also report string lists (shown below in AccessPoints which the above answer could not handle). Note that the output is aligned such as:

Name         : Omegaman
ID           : 1
Role         : Admin
AccessPoints : Alpha, Beta, Gamma
WeekDays     : Mon, Tue
StartDate    : 3/18/2014 12:16:07 PM

Below is the extension which takes in any type as long as its a class. It then reflects off of the public and private properties and if they are not null reports them.

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}}} : {{1}}", 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)))));
}

Usage

myInstance.ReportAllProperties()

Note that this is based off my blog article C#: ToString To Report all Properties Even Private Ones Via Reflection which provides a more robust explanation of what is going on.

回忆追雨的时光 2025-01-13 02:48:22

我会使用 JSON,Serializer 将为您完成所有艰苦的工作:

    public static class ObjectExtensions
    {
        public static string ToStringEx(this object obj)
        {
            return JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true });
        }
    }

I would use JSON, Serializer will do all the hard work for you:

    public static class ObjectExtensions
    {
        public static string ToStringEx(this object obj)
        {
            return JsonSerializer.Serialize(obj, new JsonSerializerOptions { WriteIndented = true });
        }
    }
假面具 2025-01-13 02:48:22

这是我发现的,适用于大多数复杂类型(包括列表):

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

This is what I found, that works with most compicated-types (including 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; }
}

usage:

string classAasString = ClassToXml.ToXml(a, typeof(ClassA)); //whare ClassA is an object
清风无影 2025-01-13 02:48:22

我自己遇到了这个问题,我正在寻找一个选项来序列化为可读的内容。如果没有只读属性,则 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;
        }
    }

I ran into this myself where I am looking for an option to serialize into something readable. If there are no read only properties xml serialization can give a readable string. However if there are read only properties / fields then xml serialization is not an option.

    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;
        }
    }
愁杀 2025-01-13 02:48:22

所以我写了一个扩展方法,调用一个已经解决了所有巫术的库。

“覆盖字符串 ToS​​tring()”与(我的)“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 core 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 链接:

< a href="https://github.com/thomasgalliker/ObjectDumper" rel="nofollow noreferrer">https://github.com/thomasgalliker/ObjectDumper

So I wrote an extension method that calls a library that has already figured out all the voodoo.

"override string ToString()" vs (my) "ToStringDump"....

Before I show the code, the reason I like the extension method (ToStringDump in this case).. better, is that I don't have to riddle my POCO/DTO objects with ObjectDump references. I believe POCOs and DTOs should be "very very clean", and even isolated in their own assembly. This way, these poco/dto objects are easily shared.

public static class ObjectDumpAdapter
{
    public static string ToStringDump(this object obj)
    {
        string returnValue = ObjectDumper.Dump(obj);
        return returnValue;
    }
}

My dotnet core 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 link:

https://www.nuget.org/packages/ObjectDumper.NET/


Quote:

ObjectDumper is a utility which aims to serialize C# objects to string
for debugging and logging purposes.

(from https://nugetmusthaves.com/Package/ObjectDumper.NET )


GitHub link:

https://github.com/thomasgalliker/ObjectDumper

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文