Component-Oriented Development


Because C# is designed to develop components, it has many features that make developing and using components easier.

Properties

Users like simplicity when they deal with objects. When dealing with a button on a form, for example, users like to write code such as

 cancelButton.caption = "Cancel"; 

where the caption field of the button is directly accessed. This is also efficient code, as the field is directly modified.

Unfortunately, this simple model makes things more difficult for the user. The point of updating the caption on a button is to actually change the caption. Because the user is directly modifying the field, however, the framework author is forced to add another step to the process:

 cancelButton.caption = "Cancel";  cancelButton.Paint(); 

This is nonoptimal, as it forces the user to remember to call Paint() to make the change happen.

Another option for the framework author is to use the property design pattern. Instead of exposing a caption field, the author exposes the functions

 string GetCaption();  void SetCaption(string caption); 

where the SetCaption() function performs the Paint() operation for the user. The user then writes

 cancelButton.SetCaption("Cancel"); 

This approach works, but instead of working with a simple field, the user of the Button class now needs to find the Get and Set functions, figure out that they're related , and write slightly more verbose code.

Properties in C# allow the framework author to use the property pattern while allowing the user to use the simple field model. The author of the button class would write the following property:

 public string Caption  {     get     {         return caption;     }     set     {         caption = value;         Paint();     } } 

The user could then write the following code:

 cancelButton.caption = "Cancel"; 

Thus, properties provide a considerable simplification when dealing with components.

Design Choice

The runtime environment also provides considerable flexibility in the way that properties can operate . In C#, however, they're exposed as "virtual fields." Although the author of a property writes code for the get and set accessors, and the compiler emits these as get and set methods , from the user's perspective a property is something that behaves like a field.

As a consequence, accessibility specifiers such as public and modifiers such as virtual and abstract can be applied only at the property level, not at the accessor level. While this complicates some useful idioms ”the most common being the "public get protected set" idiom ”the simplification in the user model is important.

Indexers

It's sometimes useful to be able to use a class like an array. In the .NET Framework, for example, there is a class called ArrayList , which is a dynamically sized array. To get and set the values in an ArrayList would require a couple of functions:

  • object GetItem(int index);

  • void SetItem(int index, object value);

Like the property design pattern, this feature makes using the code more complex, but more importantly, it makes an ArrayList work differently than an array. To allow the array model to be used by other classes, C# allows the user to write an indexer:

 public object this[int index]  {     get     {         return items[index];     }     set     {         items[index] = value;     } } 

which then allows the user to index an ArrayList directly.

Design Choice

The runtime environment supports parameterized properties, which are simply properties that take parameters. In Visual Basic .NET, a class can have more than one parameterized property, and there's nothing special about such properties.

In C#, a parameterized property is exposed as a virtual array, allowing an object to be indexed as an array. A collection class, for example, is made up of its elements, and therefore indexing to get the elements is a good model.

C# supports only a single parameterized property, though it can be overloaded with different parameter types.

Operator Overloading

C# supports operator overloading to allow users to create types that operate in the same manner as the types directly supported by the runtime. [5] Users can overload unary operators, binary operators, and comparison operators. Additionally, they can overload true and false to support nullable types.

[5] In fact, the Decimal type is a user-written type; it's not directly supported by the execution engine.

Design Choice

Operator overloading adds a fair amount of complexity to a language, but it's invaluable in creating types that work like the built-in ones. Perhaps the best example of such types is the SQL data types, which work like the built-in types but also support the SQL concept of nullability, both for expressions and comparison. [6]

[6] In other words, if you compare two SQLInt instances, and they're both null, they won't be the same; by SQL rules, null != null .

Attributes

Attributes allow the user to annotate code with information that is stored in the metadata and is then available for query at runtime.

 In C#, attributes are written in square brackets:  [MarshalAs(UnmanagedType.LPTStr)] 

If an attribute has no parameters, the parentheses can be omitted:

 [NonSerialized] 

If an element has multiple attributes, they can either be written in separate sets of square brackets or appear as a comma-separated list within a single set of brackets.

To resolve the name of an attribute, the C# compiler will first look for a class derived from System.Attribute that has the exact name. If that class is not found, the compiler will append Attribute to the name and try again.

In some locations, the element to which the attribute applies is ambiguous. In a usage such as

 [MyAttribute("Value")]  public int MyMethod(); 

the attribute could apply either to the method or to the return value. To eliminate the ambiguity, C# specifies the default element for all ambiguous cases, and then allows the user to specify a different element if desired:

 [returnValue: MyAttribute("Value")]  public int MyMethod(); 

Delegates

Delegates are used to encapsulate a function to call and (for instance methods) a specific instance to call upon. In C#, all delegates are expressed as multicast delegates.

Design Choice

The C# language provides special syntax to make it easier to perform delegate operations. The " += " operator is used to combine delegates, and the " -= " operator is used to remove a delegate from another.

In other words, when the user writes

 myDelegate += new MyEventHandler(myRoutine); 

the compiler converts it to

 myDelegate = (MyEventHandler)          Delegate.Combine(myDelegate,                      new MyEventHandler(myRoutine)); 

The compiler performs a similar replacement with " -= " and Delegate.Remove() .

Events

Events can be thought of as properties on top of delegates, providing options both to control what happens in the accessor and to limit access to the underlying backing variable.

In C#, there are two ways to deal with events. In the simple event syntax, the user simply writes

 public event MyEventHandler OnClick; 

This statement declares a private delegate named OnClick and creates the event OnClick , writing the appropriate thread-safe add_OnClick() and remove_OnClick() functions. The user of a class can hook up to an event using the sam " += " and " -= " operators as are used with delegates, although for an event the operators call add_OnClick() and remove_OnClick() .

The simple syntax works well for most cases, but does not provide sufficient control for advanced users. The auto-allocated delegate field is not a good choice for objects that support lots of events, but typically have few delegates hooked to them. [7]

[7] The Windows Forms controls are an example.

C# therefore provides an advanced syntax. In this syntax, the user writes the add and remove functions, using a syntax similar to properties:

 public event MyEventHandler OnClick  {     add     {         // add code here     }     remove     {         // remove code here     } } 

In this variation, the user is responsible for allocating space to store the delegate, writing appropriate add and remove code, and making the operations thread-safe.



Programming in the .NET Environment
Programming in the .NET Environment
ISBN: 0201770180
EAN: 2147483647
Year: 2002
Pages: 146

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net