Improve C # program 50 Methods clause 5: always provide tostring () method

Source: Internet
Author: User

System. Object. tostring () is probably the most common method in. net. We should provide a reasonable version for all the customer code of our class. Otherwise, these code can only use some attributes of our class to customize the readable representation. String Representation of the type is very useful. It can display information about objects to users in many places, such as in Windows Forms, web forms, console output windows, and debugging environment. Therefore, the tostring () method of the object class should be rewritten for each type we create. If you create a more complex type, you should implement the iformattable. tostring () method. If we didn't rewrite this method, or did not write well enough, then the customer code that uses them should be fixed by ourselves.

The default tostring () method provided by system. Object returns the type name. Such information is generally useless. strings like "rect", "point", and "size" are mostly not what we want to display to users. However, if we do not override the tostring () method of the object, the user will see this. We only need to write it once, but customers will enjoy it countless times. A little effort can benefit many people (including ourselves.

Let's take a look at the simplest requirement of rewriting system. Object. tostring. The main function of this method is to provide the most common text representation for the type. For example, consider the following Customer class with three fields:

Public Class Customer

{

Private string _ name;

Private decimal _ revenue;

Private string _ contactphone;

}

If the override version is not provided, customer inherits the tostring () method of the object class, that is, a "customer" string is returned. This string is useless. Even if the tostring () method is only used for debugging purposes, it should output a more meaningful string. When rewriting, we should try our best to consider the customer's desired representation. For the customer class, returning _ name is a good choice:

Public override string tostring ()

{

Return _ name;

}

Even if you do not follow other suggestions in these terms, follow the practices shown here. It can save a lot of time. After we override the tostring () method for the customer class, the objects of this class can be easily added to the Windows Forms control, web forms control, or console .. Net FCL uses the override version of object. tostring () when displaying objects to various controls (such as combo box, list box, and text box. If we create a list of customer objects in Windows Forms or web forms, the text will be the name of customer (_ name ). The system. Console. writeline () Method and System. String. Format () method also call the tostring () method. As long as. Net FCL needs to obtain the string representation of the customer, our customer type will respond with its name (_ name. Only one method with three lines of code can be provided to handle all these basic requirements.

Although the simple tostring () method can meet our needs many times, sometimes we still need a more powerful method. The preceding customer type has three fields: _ name, _ revenue, and _ contactphone. We only use the _ name field. We can solve this problem by implementing the iformattable interface. The iformattable Interface contains an overloaded tostring () method, which allows us to specify certain format information for the type. This interface is useful when we need to create different forms of string output for the type. The customer type is an example. For example, some users may want to create a report that contains the customer's name and income from the previous year in the form of a table. The iformattable. tostring () method allows you to specify a certain format of string output for our type. The signature is as follows:

String System. iformattable. tostring (string format,

Iformatprovider formatprovider)

We can use a format string to specify our own format for our type. For example, a specific character is used to indicate certain format information. In the example of customer type, we can use N to represent name, R to represent revenue, and P to represent phone. You can also specify the combination of these characters. The following code shows a possible practice:

# Region iformattable members

// Supported formats:

// Use N to represent name.

// Use R to represent revenue.

// Use P to indicate contact phone.

// Supports combination formats such as NR, NP, and NPR.

// "G" indicates the common format.

String System. iformattable. tostring (string format,

Iformatprovider formatprovider)

{

If (formatprovider! = NULL)

{

Icustomformatter FMt = formatprovider. getformat (

This. GetType ())

As icustomformatter;

If (FMT! = NULL)

Return FMT. Format (format, this, formatprovider );

}

Switch (Format)

{

Case "R ":

Return _ revenue. tostring ();

Case "p ":

Return _ contactphone;

Case "Nr ":

Return string. Format ("{}, {: c }",

_ Name, _ revenue );

Case "NP ":

Return string. Format ("{0, 20}, {1, 15 }",

_ Name, _ contactphone );

Case "PR ":

Return string. Format ("{}, {: c }",

_ Contactphone, _ revenue );

Case "PN ":

Return string. Format }",

_ Contactphone, _ name );

Case "RN ":

Return string. Format ("{: C }",

_ Revenue, _ name );

Case "RP ":

Return string. Format ("{: C }",

_ Revenue, _ contactphone );

Case "NRP ":

Return string. Format ("{}, {: c }",

_ Name, _ revenue, _ contactphone );

Case "NPR ":

Return string. Format ("{}, {}, {: c }",

_ Name, _ contactphone, _ revenue );

Case "PNR ":

Return string. Format ("{}, {}, {: c }",

_ Contactphone, _ name, _ revenue );

Case "PRN ":

Return string. Format ("{}, {: c }",

_ Contactphone, _ revenue, _ name );

Case "RPN ":

Return string. Format ("{: C }",

_ Revenue, _ contactphone, _ name );

Case "RNP ":

Return string. Format ("{: C }",

_ Revenue, _ name, _ contactphone );

Case "N ":

Case "G ":

Default:

Return _ name;

}

}

# Endregion

Add this function so that customers of the customer type can customize the customer type representation:

Iformattable C1 = new customer ();

Console. writeline ("customer record: {0 }",

C1.tostring ("NRP", null ));

Generally, the implementation of iformattable. tostring () varies by type, but some work needs to be processed in every type. First, we must support "G" that represents "General Format ". Second, we must support two types of "null format", namely "" and null. The returned strings must be the same as the strings returned by the override version of object. tostring .. Net FCL calls iformattable. tostring () instead of object. tostring () for each type that implements the iformattable interface ().. Net FCL usually uses a null format string to call iformattable. tostring (), but in a small part, "G" is used to represent the general format. If our types support the iformattable interface but do not support these standard formats, we will break the automatic string conversion rules in FCL.

The second parameter of the iformattable. tostring () method is an object that implements the iformatprovider interface. This object allows the client program to provide some unexpected formatting options. If you look at the previous implementation of iformattable. tostring (), there will always be some formatting options that we expect but do not actually provide. If we want to provide outputs that are easy to understand, this situation is inevitable. No matter how many formatting options we support, users will expect some unexpected format one day. This is the first few lines of work in the above code example: Find the object that has implemented the iformatprovider interface, and then submit the formatting task to the icustomformatter.

Next, we will transfer our perspective from the author of the class to the user of the class. Assume that the expected format is not supported. For example, the number of names of some customers must be greater than 20. In this case, we want to provide a name with 50 characters. This is the application of the iformatprovider interface. We need to create two classes: one implementing the iformatprovider interface and the other implementing the icustomformatter interface-This class is used to create custom output formats. The iformatprovider interface defines a method: getformat (), which returns an object that implements the icustomformatter interface. The icustomformatter Interface contains the methods for actually executing formatting. The following code outputs a name with 50 characters:

// Iformatprovider example:

Public class customformatter: iformatprovider

{

# Region iformatprovider members

// Iformatprovider only contains one method.

// This method returns an object in the specified Interface format.

// Generally, only icustomformatter is implemented.

Public object getformat (type formattype)

{

If (formattype = typeof (icustomformatter ))

Return new customerformatprovider ();

Return NULL;

}

# Endregion

// A nested class that provides a custom format for the customer class.

Private class customerformatprovider: icustomformatter

{

# Region icustomformatter members

Public string format (string format, object Arg,

Iformatprovider formatprovider)

{

Customer c = Arg as customer;

If (C = NULL)

Return Arg. tostring ();

Return string. Format ("{}, {}, {: c }",

C. Name, C. contactphone, C. Revenue );

}

# Endregion

}

}

The above getformat () method creates an object that implements the icustomformatter interface. The icustomformatter. Format () method performs the actual formatting output in the specified way and converts the object to a string format. We can define the format parameter for the icustomformatter. Format () method to specify multiple formatting options. The formatprovider parameter is an iformatprovider object used to call the getformat () method.

To specify a custom format, you need to explicitly call the string. Format () method and pass an iformatprovider object:

Console. writeline (string. Format (New customformatter (),

"", C1 ));

Whether or not a class implements the iformattable interface, we can create an implementation class for iformatprovider and icustomformatter. Therefore, even if the original author of a class does not provide reasonable tostring () behavior, we can still provide formatting support for it. Of course, as an external visitor of a class, we can only construct strings by accessing the public attributes and data members. Although writing two classes (iformatprovider and icustomformatter) requires a lot of work, and its purpose is only to get a string. However, once we use this method to implement our own defined string output, they will be supported everywhere in the. NET Framework.

Now let's go back to the class author role. Rewriting object. tostring () is the simplest way to provide string representation for the class. This method is required every time we create a type. It should be the most obvious and commonly used expression of our type. The iformattable interface should be implemented only when we expect more complex output formats for types. It provides a standard method for "custom string output for type users. If we do not do this, you need to customize the formatter yourself. This method requires more code because the user is out of class and cannot access the internal state of the object.

People always need to obtain type information, and strings are the easiest to understand. We should actively do this, and rewriting the tostring () method of all types may be the simplest in all practices.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.