Metaprograming in C# : Automatic ToString Method
Asked Answered
R

7

9

I have some classes which only serve to contain data. For example

public class EntityAdresse : IEntityADRESSE
{
    public string Name1 { get; set; }
    public string Strasse { get; set; }
    public string Plz { get; set; }
    public string Ort { get; set; }
    public string NatelD { get; set; }
    public string Mail { get; set; }
    public int Id_anrede { get; set; }
    public string Telefon { get; set; }
    public int Id_adr { get; set; }
    public int Cis_adr { get; set; }
}

This represents a address. Like I said, it only contains data. No Methods (I know the interface doesn't make sense here...)

Now I need to implement ToString for all this Entity-Classes and there are a lot of them.

My question is: Is there a metaprograming feature in C# which generates this tostring methods automaticaly? I don't want to write boiler plate code for every which of these classes.

Alternatively I could also write a perl or python script to generate the code. But I prefer doing it in C# directly.

Ranchman answered 6/3, 2013 at 10:5 Comment(0)
T
11

Generally, you need to obtain all property values of your class and combine them into a single string. This can be done using the following approach:

public override string ToString() 
{
    PropertyDescriptorCollection coll = TypeDescriptor.GetProperties(this);
    StringBuilder builder = new StringBuilder();
    foreach(PropertyDescriptor pd in coll)
    {
        builder.Append(string.Format("{0} : {1}", pd.Name , pd.GetValue(this).ToString()));
    }
    return builder.ToString();
}
Tuatara answered 6/3, 2013 at 10:14 Comment(2)
It will have to display the property's name as well probably.Dygall
@Tuatara You could update the answer with a 'null' check on 'pd.GetValue(this)'. I was getting a NullPointer on the toString in that case.Canvasback
S
4

A short version of what's already been said:

public override string ToString()
{
    var propertyStrings = from prop in GetType().GetProperties()
                          select $"{prop.Name}={prop.GetValue(this)}";
    return string.Join(", ", propertyStrings);
}
Showily answered 16/11, 2018 at 23:49 Comment(1)
Best one by farRobledo
V
3

The feature is called reflection. A simplest example would be:

  public class EntityBase
  {
      public override string ToString()
      {
          StringBuilder sb = new StringBuilder();

          foreach ( var property in this.GetType().GetProperties() )
          {
              sb.Append( property.GetValue( this, null ) );
          }

          return sb.ToString();
      } 
  }

  public class TheEntity : EntityBase
  {
      public string Foo { get; set; }
      public string Bar { get; set; }
  }

Please finetune it to fulfill your requirements.

As you can see the idea is to have a single implementation in a base class so that all descendands automatically inherit the same behavior.

Varletry answered 6/3, 2013 at 10:17 Comment(2)
sb.AppendFormat( "{0} {1}", property.Name, property.GetValue( this, null ) );Varletry
Good job but... you can't extends more than EntityBase in this caseWillettawillette
C
2

There isn't a feature built into the language to do this automatically, but you could write a library to do it using the Expression features in the framework to generate a function to do it.

You'd have a function like this:

Func<T,string> GenerateToString<T>()

And in your class you have something like this:

public class EntityAdresse : IEntityADRESSE
{
    private static readonly Func<EntityAdresse,string> s_ToString=Generator.GenerateToString<EntityAdresse>();

    public string Name1 { get; set; }
    public string Strasse { get; set; }
    public string Plz { get; set; }
    public string Ort { get; set; }
    public string NatelD { get; set; }
    public string Mail { get; set; }
    public int Id_anrede { get; set; }
    public string Telefon { get; set; }
    public int Id_adr { get; set; }
    public int Cis_adr { get; set; }

    public override ToString()
    {
       return s_ToString(this);
    }
}

The challenge is writing GenerateToString. Using the Expression framework and reflection you'll be able to create a delegate that is as efficient as if you'd written the code by hand.

You could use reflection on it's own, but the performance hit will soon start to be an issue.

Coenzyme answered 6/3, 2013 at 10:19 Comment(0)
D
2

There is an open source framework StatePrinter for automatic ToString generation. It is very configurable so it should cater for your needs. The introspection code can be found at Introspection

Diomedes answered 6/4, 2014 at 11:57 Comment(0)
E
0

Consider using a Record Type. A Record Type will auto-magically generate a display conscious ToString() method at compile time.

Eleanoreleanora answered 15/1, 2024 at 18:21 Comment(0)
E
0

Adding this since it's not been mentionned, but adding

[System.Serializable] struct YourType {}

Would allow you to easily serialize it to your preferred format

Eleonoraeleonore answered 16/7, 2024 at 19:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.