6.9 Generating Code That Is No Longer in Your Main Code Paths

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 5

UInt16: 4

UInt32: 4
UInt64: 4

See Also
The “Partial Class Definitions” and “partial Keyword” topics in the MSDN
documentation.

6.9 Generating Code That Is No Longer in Your Main


Code Paths
Problem
Occasionally, as a developer, you run into a situation in which it would be handy to
be able to regenerate your class based on a set of data that can change. You need to
be able to do this without destroying all of the logic you have already created or
causing yourself a painful merge between an old and a new class file.

Solution
Write a utility that can regenerate the code that is dependent on external data and
keep the generated code in a separate file that defines a partial class. To demonstrate
this, we have created a Visual Studio 2008 add-in called PartialClassAddin in the
sample code that will allow you to enter a class name and then select which
attributes to apply to the class. This is a standard add-in generated by selecting the
add-in template from the project wizard. Its main dialog box is shown in Figure 6-1.
Enter a class name, MyNewClass, select the System.CLSCompliantAttribute and the
System.SerializeableAttribute from the list, and click the OK button. This gener-
ates the MyNewClass_Attributes.cs file with the following in it:
// Using directives
using System;

namespace NamespaceForMyNewClass
{
#region Attributes
[System.CLSCompliant(true)]
[System.Serializable( )]
#endregion // Attributes

public partial class MyNewClass


{
public MyNewClass( )
{
}
}
}

234 | Chapter 6: Iterators, Partial Types, and Partial Methods


writer.WriteEndElement( );
writer.WriteStartElement("Contact");
writer.WriteAttributeString("name", "Newman");
writer.WriteAttributeString("phone", "666-666-6666");
writer.WriteEndElement( );
writer.WriteStartElement("Contact");
writer.WriteAttributeString("name", "Harold");
writer.WriteAttributeString("phone", "777-555-3333");
writer.WriteEndElement( );
writer.WriteEndElement( );
}

This method will give you similar output like this:


<AddressBook>
<Contact name="Tim" phone="999-888-0000" />
<Contact name="Newman" phone="666-666-6666" />
<Contact name="Harold" phone="777-555-3333" />
</AddressBook>

Or you can use the XmlDocument class to programmatically construct the XML:
public static void CreateXml( )
{
// Start by making an XmlDocument.
XmlDocument xmlDoc = new XmlDocument( );
// Create a root node for the document.
XmlElement addrBook = xmlDoc.CreateElement("AddressBook");
xmlDoc.AppendChild(addrBook);
// Create the Tim contact.
XmlElement contact = xmlDoc.CreateElement("Contact");
contact.SetAttribute("name","Tim");
contact.SetAttribute("phone","999-888-0000");
addrBook.AppendChild(contact);
// Create the Newman contact.
contact = xmlDoc.CreateElement("Contact");
contact.SetAttribute("name","Newman");
contact.SetAttribute("phone","666-666-6666");
addrBook.AppendChild(contact);
// Create the Harold contact.
contact = xmlDoc.CreateElement("Contact");
contact.SetAttribute("name","Harold");
contact.SetAttribute("phone","777-555-3333");
addrBook.AppendChild(contact);
// Display XML.
Console.WriteLine("Generated XML:\r\n{0}",addrBook.OuterXml);
Console.WriteLine( );
}

This method gives the output like this:


Generated XML:
<AddressBook><Contact name="Tim" phone="999-888-0000" /><Contact name="Newman"
phone="666-666-6666" /><Contact name="Harold" phone="777-555-3333" /></AddressBook>

Creating an XML Document Programmatically | 565


AsyncAction aa2 = new AsyncAction( );
aa2.CallbackAsyncDelegate( );

The output for this code is shown next. Note that the thread ID for Method1 is
different:
Calling BeginInvoke on Thread 9
Invoked Method1 on Thread 10
Getting callback on Thread 10
retVal (Callback): 1

Discussion
The asynchronous delegates in this recipe are created and invoked in the same fash-
ion as the asynchronous delegate in Recipe 18.3. Instead of using the IsCompleted
property to determine when the asynchronous delegate is finished processing (or the
WaitOne method to block for a specified time while the asynchronous delegate contin-
ues processing), This recipe uses a callback to indicate to the calling thread that the
asynchronous delegate has finished processing and that its return value, ref parame-
ter values, and out parameter values are available.
Invoking a delegate in this manner is much more flexible and efficient than simply
polling the IsCompleted property to determine when a delegate finishes processing.
When polling this property in a loop, the polling method cannot return and allow
the application to continue processing. A callback is also better than using a WaitOne
method, since the WaitOne method will block the calling thread and allow no process-
ing to occur.
The CallbackAsyncDelegate method in this recipe makes use of the first parameter to
the BeginInvoke method of the asynchronous delegate to pass in another delegate.
This contains a callback method to be called when the asynchronous delegate fin-
ishes processing. After calling BeginInvoke, this method can now return, and the
application can continue processing; it does not have to wait in a polling loop or be
blocked while the asynchronous delegate is running.
The AsyncInvoke delegate that is passed into the first parameter of the BeginInvoke
method is defined as follows:
public delegate void AsyncCallback(IAsyncResult ar)

When this delegate is created, as shown here, the callback method passed in,
DelegateCallback, will be called as soon as the asynchronous delegate completes:
AsyncCallback callBack = new AsyncCallback(DelegateCallback);

DelegateCallback will not run on the same thread as BeginInvoke but rather on a
Thread from the ThreadPool. This callback method accepts a parameter of type
IAsyncResult. You can cast this parameter to an AsyncResult object within the
method and use it to obtain information about the completed asynchronous dele-
gate, such as its return value, any ref parameter values, and any out parameter val-
ues. If the delegate instance that was used to call BeginInvoke is still in scope, you can

Being Notified of the Completion of an Asynchronous Delegate | 729


foo = "--TEST--";
Console.WriteLine(foo.TrimEnd(new char[] {'-'})); // Displays "--TEST"

foo = ",-TEST-,-";
Console.WriteLine(foo.TrimEnd(new char[] {'-',','})); //Displays ",-TEST"

Discussion
The Trim method is most often used to eliminate whitespace at the beginning and
end of a string. In fact, if you call Trim without any parameters on a string variable,
this is exactly what happens. The Trim method is overloaded to allow you to remove
other types of characters from the beginning and end of a string. You can pass in a
char[] containing all the characters that you want removed from the beginning and
end of a string. Note that if the characters contained in this char[] are located some-
where in the middle of the string, they are not removed.
The TrimStart and TrimEnd methods remove characters at the beginning and end of a
string, respectively. These two methods are not overloaded, unlike the Trim method.
Rather, these two methods accept only a char[]. If you pass a null into either one of
these methods, only whitespace is removed from the beginning or the end of a string.

See Also
The “String.Trim Method,” “String.TrimStart Method,” and “String.TrimEnd
Method” topics in the MSDN documentation.

2.17 Testing a String for Null or Empty


Problem
You need a quick and easy way to check if a string is either null or of zero length.

Solution
Use the static IsNullOrEmpty method of the String class:
bool stringTestResult = String.IsNullOrEmpty(testString);

Discussion
The IsNullOrEmpty method is a very convenient method in that it allows you to test a
string for null or zero length with a single method call. This method returns true if
the string passed in to it is equal to one of the following:
• Null
• String.Empty
Otherwise, this method returns false.

66 | Chapter 2: Strings and Characters


each subpart or the expression into separate methods for each part of the expression
and then combine the methods to get the final result.
To fix the expression presented in the Problem section, rewrite it as follows:
double radius1 = 2;
double radius2 = 4;
double aveArea = .5 * (Math.PI * Math.Pow(radius1, 2) + Math.PI *
Math.Pow(radius2, 2));

Notice the addition of the parentheses; these parentheses cause the area of the two cir-
cles to be calculated and added together first. Then the total area is multiplied by .5.
This is the behavior you are looking for. An additional benefit is that the expression
can become easier to read as the parentheses provide clear distinction of what part of
the expression is to be evaluated first. This technique works equally well with Bool-
ean equations.

Discussion
Parentheses are key to writing maintainable and bug-free equations. Not only is your
intention clearly spelled out, but you also override any operator precedence rules
that you might not have taken into account. In fact, the only way to override opera-
tor precedence is to use parentheses. Consider the following equation:
int x = 1 * 2 - -50 / 4 + 220 << 1;
Console.WriteLine("x = " + x);

The value 468 is displayed for this equation.


This is the same equation written with parentheses:
int y = ((1 * 2) - ((-50) / 4) + 220) << 1;
Console.WriteLine("y = " + y);

The same value (468) is also displayed for this equation. Notice how much easier it is
to read and understand how this equation works when parentheses are used. How-
ever, it is possible to get carried away with the use of parentheses in an equation:
int z = ((((1 * 2) - ((-50) / 4)) + 220) << (1));
Console.WriteLine("z = " + z);

This equation also evaluates to 468, but due to the overuse of parentheses, you can
get lost determining where one set of parentheses begins and where it ends. You
should try to balance your placement of parentheses in strategic locations to prevent
oversaturating your equation with parentheses.
Another place where you can get into trouble with operator precedence is when
using a ternary operator (?:), defined as follows:
boolean condition ? true-expression : false-expression

Each type of expression used by this operator is defined as follows:

86 | Chapter 3: Classes and Structures

You might also like