Tải bản đầy đủ - 0 (trang)
13-7. Implement a Formattable Type

13-7. Implement a Formattable Type

Tải bản đầy đủ - 0trang

CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



When run on a machine configured with English (UK) regional settings, this code will result in the

output shown here:

a = 345678.5678, b = 12000, and c = 254

a = £345,679, b = 12,000.0000, and c =



000fe



As you can see, changing the contents of the format specifiers changes the format of the output

significantly, even though the data has not changed. To enable support for format specifiers in your own

types, you must implement the IFormattable interface. IFormattable declares a single method named

ToString with the following signature:

string ToString(string format, IFormatProvider formatProvider);

The format argument is a System.String containing a format string. The format string is the portion

of the format specifier that follows the colon. For example, in the format specifier {2,10:x5} used in the

previous example, x5 is the format string. The format string contains the instructions that the

IFormattable instance should use when it’s generating the string representation of its content. The .NET

Framework documentation for IFormattable states that types that implement IFormattable must

support the G (general) format string, but that the other supported format strings depend on the

implementation. The format argument will be null if the format specifier does not include a format

string component; for example, {0} or {1,20}.

The formatProvider argument is a reference to an instance of a type that implements

System.IFormatProvider, and that provides access to information about the cultural and regional

preferences to use when generating the string representation of the IFormattable object. This

information includes data such as the appropriate currency symbol or number of decimal places to use.

By default, formatProvider is null, which means you should use the current thread’s regional and

cultural settings, available through the static method CurrentCulture of the

System.Globalization.CultureInfo class. Some methods that generate formatted strings, such as

String.Format, allow you to specify an alternative IFormatProvider to use such as CultureInfo,

DateTimeFormatInfo, or NumberFormatInfo.

The .NET Framework uses IFormattable primarily to support the formatting of value types, but it

can be used to good effect with any type.



The Code

The following example contains a class named Person that implements the IFormattable interface. The

Person class contains the title and names of a person and will render the person’s name in different

formats depending on the format strings provided. The Person class does not make use of regional and

cultural settings provided by the formatProvider argument. The Main method demonstrates how to use

the formatting capabilities of the Person class.

using System;

namespace Apress.VisualCSharpRecipes.Chapter13

{

public class Person : IFormattable

{



652



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



// Private members to hold the person's title and name details.

private string title;

private string[] names;

// Constructor used to set the person's title and names.

public Person(string title, params string[] names)

{

this.title = title;

this.names = names;

}

// Override the Object.ToString method to return the person's

// name using the general format.

public override string ToString()

{

return ToString("G", null);

}

// Implementation of the IFormattable.ToString method to return the

// person's name in different forms based on the format string

// provided.

public string ToString(string format, IFormatProvider formatProvider)

{

string result = null;

// Use the general format if none is specified.

if (format == null) format = "G";

// The contents of the format string determine the format of the

// name returned.

switch (format.ToUpper()[0])

{

case 'S':

// Use short form - first initial and surname.

result = names[0][0] + ". " + names[names.Length - 1];

break;

case 'P':

// Use polite form - title, initials, and surname.

// Add the person's title to the result.

if (title != null && title.Length != 0)

{

result = title + ". ";

}

// Add the person's initials and surname.

for (int count = 0; count < names.Length; count++)

{

if (count != (names.Length - 1))

{

result += names[count][0] + ". ";

}



653



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



else

{

result += names[count];

}

}

break;

case 'I':

// Use informal form - first name only.

result = names[0];

break;

case 'G':

default:

// Use general/default form - first name and surname.

result = names[0] + " " + names[names.Length - 1];

break;

}

return result;

}

}

// A class to demonstrate the use of Person.

public class Recipe13_07

{

public static void Main()

{

// Create a Person object representing a man with the name

// Mr. Richard Glen David Peters.

Person person =

new Person("Mr", "Richard", "Glen", "David", "Peters");

// Display the person's name using a variety of format strings.

System.Console.WriteLine("Dear {0:G},", person);

System.Console.WriteLine("Dear {0:P},", person);

System.Console.WriteLine("Dear {0:I},", person);

System.Console.WriteLine("Dear {0},", person);

System.Console.WriteLine("Dear {0:S},", person);

// Wait to continue.

Console.WriteLine(Environment.NewLine);

Console.WriteLine("Main method complete. Press Enter");

Console.ReadLine();

}

}

}



654



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS



Usage

When executed, the preceding example produces the following output:

Dear Richard Peters,

Dear Mr. R. G. D. Peters,

Dear Richard,

Dear Richard Peters,

Dear R. Peters,



13-8. Implement a Custom Exception Class

Problem

You need to create a custom exception class so that you can use the runtime’s exception-handling

mechanism to handle application-specific exceptions.



Solution

Create a serializable class that extends the System.Exception class. Add support for any custom data

members required by the exception, including constructors and properties required to manipulate the

data members.



How It Works

Exception classes are unique in the fact that you do not declare new classes solely to implement new or

extended functionality. The runtime’s exception-handling mechanism—exposed by the C# statements

try, catch, and finally—works based on the type of exception thrown, not the functional or data

members implemented by the thrown exception.

If you need to throw an exception, you should use an existing exception class from the .NET

Framework class library, if a suitable one exists. For example, some useful exceptions include the

following:





System.ArgumentNullException, when code passes a null argument value that

does not support null arguments to your method







System.ArgumentOutOfRangeException, when code passes an inappropriately large

or small argument value to your method



655



www.it-ebooks.info



CHAPTER 13 ■ COMMONLY USED INTERFACES AND PATTERNS







System.FormatException, when code attempts to pass your method a String

argument containing incorrectly formatted data



If none of the existing exception classes meet your needs, or you feel your application would benefit

from using application-specific exceptions, it’s a simple matter to create your own exception class. In

order to integrate your custom exception with the runtime’s exception-handling mechanism and remain

consistent with the pattern implemented by .NET Framework–defined exception classes, you should do

the following:





Give your exception class a meaningful name ending in the word Exception, such

as TypeMismatchException or RecordNotFoundException.







Mark your exception class as sealed if you do not intend other exception classes to

extend it.







Implement additional data members and properties to support custom

information that the exception class should provide.







Implement three public constructors with the signatures shown here and ensure

that they call the base class constructor:

public CustomException() : base() {}

public CustomException(string msg): base(msg) {}

public CustomException(string msg, Exception inner) : base(msg, inner) {}







Make your exception class serializable so that the runtime can marshal instances

of your exception across application domain and machine boundaries. Applying

the attribute System.SerializableAttribute is sufficient for exception classes that

do not implement custom data members. However, because Exception

implements the interface System.Runtime.Serialization.ISerializable, if your

exception declares custom data members, you must override the

ISerializable.GetObjectData method of the Exception class as well as implement

a deserialization constructor with this signature. If your exception class is sealed,

mark the deserialization constructor as private; otherwise, mark it as protected.

The GetObjectData method and deserialization constructor must call the

equivalent base class method to allow the base class to serialize and deserialize its

data correctly. (See recipe 13-1 for details on making classes serializable.)



■ Tip In large applications, you will usually implement quite a few custom exception classes. It pays to put

significant thought into how you organize your custom exceptions and how code will use them. Generally, avoid

creating new exception classes unless code will make specific efforts to catch that exception; use data members

to achieve informational granularity, not additional exception classes. In addition, avoid deep class hierarchies

when possible in favor of broad, shallow hierarchies.



656



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

13-7. Implement a Formattable Type

Tải bản đầy đủ ngay(0 tr)

×