System.Object.ToString()

Die ToString() Methode ist eine der am meisten verwendeten Funktionen im .Net Framework. Sie ist die einzige Methode die von System.Object implementiert wird und deshalb bei jedem Objekt verfügbar ist – ganz egal von welchem Typ.

Die ToString()-Methode erlaubt die Repräsentation eines Objektes als String. Wird sie nicht angegeben, muss jeder Benutzer der Klasse immer selber entscheiden (und entwickeln), wie die Klasse dargestellt wird. Besonders beim Databinding ist das
ein immer wiederkehrender Task.

Es sollte also immer ein sinnvoller “override” gemacht werden, der eine sinnvolle Darstellung des Objektes als string zurück-gibt. Im einfachsten Fall sieht die Implementierung einfach so aus:

public class Product
{
    public int ProductId { get; set; }

    public string Name { get; set; }

    public double Price { get; set; }

    public override string ToString()
    {
        return this.Name;
    }
}

Wenig Aufwand, der trotzdem hinterher vieles Einfacher macht. Egal ob WPF, Silverlight oder WinForms…

Wird es etwas komplizierter, kann IFormattable.ToString(string format, IFormatProvider formatProvider) verwendet werden.

public class Product : IFormattable
{
    public int ProductId { get; set; }

    public string Name { get; set; }

    public double Price { get; set; }

    public override string ToString()
    {
        return this.Name;
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider != null)
        {
             ICustomFormatter formatter = formatProvider.GetFormat(this.GetType()) as ICustomFormatter;
             if (formatter != null)
             {
                 return formatter.Format(format, this, formatProvider);
             }
        }

        switch (format)
        {
             case "i":
                 return ProductId.ToString();

             case "p":
                 return Price.ToString(formatProvider);

             case "f":
                 return string.Format(formatProvider, "Product: {0} - {1} - {2}", ProductId, Name, Price);

             default:
                 return this.ToString();
         }
     }
}

Auf diese Weise kann man eigene Formatierungsoptionen für seinen Typ angeben. Außerdem bleibt der Type einfach erweiterbar, indem man ICustomFormatter implementiert. Dies könnte so aussehen:

public class ProductFormatter : IFormatProvider, ICustomFormatter
{
    IFormatProvider priceProvider;

    public ProductFormatter()
    {
        this.priceProvider = null;
    }
 
    public ProductFormatter(IFormatProvider priceProvider)
    {
        this.priceProvider = priceProvider;
    }
    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        var product = arg as Product;

        if (product == null)
            return string.Empty;

        return string.Format("{0} ({1})", product.Name, product.Price.ToString(format, priceProvider));
    }
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof(Product))
        {
            return this;
        }
        else
        {
            return null;
        }
    }
}

Man sieht in dem Beispiel, wie schön diese Optionen verschachtelt und an untere Typen weitergereicht werden könne. Das Ergebnis würde so aussehen:

[TestClass]
public class ToStringTest
{
    [TestMethod]
    public void FormatProductTest()
    {
        var p = new Product { Name = "Sudoku X600", Price = 115.10, ProductId = 666 };

        Assert.AreEqual("Sudoku X600", p.ToString());
        Assert.AreEqual("666", p.ToString("i", null));
        Assert.AreEqual("115,1", p.ToString("p", null));
        Assert.AreEqual("Product: 666 - Sudoku X600 - 115,1", p.ToString("f", null));
        Assert.AreEqual("115,1", p.ToString("p", new CultureInfo("de-DE")));
        Assert.AreEqual("Product: 666 - Sudoku X600 - 115,1", p.ToString("f", new CultureInfo("de-DE")));
    }

    [TestMethod]
    public void UseCustomFormatter()
    {
        var p = new Product { Name = "Sudoku X600", Price = 115.10, ProductId = 666 };

        Assert.AreEqual("Sudoku X600 (115,10 €)", p.ToString("C2", new ProductFormatter()));
        Assert.AreEqual("Sudoku X600 (115,10 €)", p.ToString("C2", new ProductFormatter(new CultureInfo("de-DE"))));
        Assert.AreEqual("Sudoku X600 ($115.10)", p.ToString("C2", new ProductFormatter(new CultureInfo("en-US"))));
    }
}

Immer eine Überschreibung für ToString() angeben

Für komplexere Formatierungen IFormattable verwenden, damit Klienten auch eigene Formatter verwenden können.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s