1.14 Properties
A is the named attribute associated with an object or a class. Examples of properties include the length of a string, the size of a font, the caption of a window, the name of a customer , and so on. Properties are a natural extension of Fields–both are named members with associated types, and the syntax for accessing Fields and properties is the same. However, unlike fields, properties do not denote storage locations. Instead, properties have accessors that specify the statements to execute in order to read or write their values. Properties thus provide a mechanism for associating actions with the reading and writing of object ' s attributes, and th EY Furthermore permit such attributes to be computed.
The success of rapid application development tools like Visual Basic can, to some extent, being attributed to the inclusion O F properties as a first-class element. VB developers can I-a property as being field-like, and I allows them to focus on their own application logic RA Ther than on the details of a component they happen to be using. On the face of it, this is difference might not seem like a big deal, but modern, component-oriented programs and tend to be chock Full of property reads and writes. Languages with Method-like usage's properties (e.g., O.setvalue (O.getvalue () + 1);) are clearly at a disadvantage compare D to languages that feature field-like usage of properties (e.g., o.value++;).
Properties are defined in C # using property declaration syntax. The syntax looks quite similar to a field declaration. The second part includes a get accessor and/or a set accessor. In the example below, the Button class defines a Caption property.
public class Button:control
{
private string caption;
public string Caption {
get {
return caption;
}
set {
Caption = value;
Repaint ();
}
}
}
Properties that can is both read and written, like the Caption property, include both get and set accessors. The get accessor was called when the property ' s value is read; The set accessor is called when the property ' s value is written. In a set accessor; The new value is given in a implicit value parameter.
Declaration of properties is relatively straightforward but the true value of properties shows itself are in their usage r Ather than in their declaration. The Caption property can read and written in the same way this fields can be read and written:
Button B = New button ();
B.caption = "ABC"; Set
string s = b.caption; Get
B.caption + + "DEF"; Get & Set
1.15 Indexers
If properties in C # can be likened to "smart fields", then indexers can is likened to "smart arrays". Whereas properties enable Field-like access, indexers enable array-like access.
As a example, consider a ListBox control, which displays strings. This class wants to expose a array-like data structure that exposes the list of strings it contains, but also wants Able to automatically update it contents when a value is altered. These goals can is accomplished by providing a indexer. The syntax for a indexer declaration are similar to this of a property declaration, with the main differences being Ndexers are nameless (the "name" used in the declaration are this, since this is being indexed) and that additional indexin G parameters are provided between square brackets.
public class Listbox:control
{
Private string[] items;
public String This[int Index] {
get {
return Items[index];
}
set {
Items[index] = value;
Repaint ();
}
}
}
As with properties, the convenience of indexers are best shown by looking in use rather than. The ListBox class can be used as follows:
ListBox listbox = ...;
Listbox[0] = "Hello";
Console.WriteLine (Listbox[0]);
1.16 Events
Events permit a class to declare notifications for which clients can attach executable code in the form of event handlers. Events are an important aspect of the "design of Class" libraries in, and of the System-provided class library in P articular. C # provides a integrated solution for events.
A class defines an event by providing a event declaration, which looks quite the similar to a field or event declaration but With an added event keyword. The type of this declaration must is a delegate type. In the example below, the Button class defines a Click event of type EventHandler.
public delegate void EventHandler (object sender, Event e);
public class Button:control
{
public event EventHandler Click;
public void Reset () {
Click = null;
}
}
Inside the Button class, the Click member can is corresponds exactly to a private field of type EventHandler. However, outside the Button class, the Click member can is used on the left hand side of the + + and-= operators. This is restricts client code to adding or removing the event handler. In the client code example below, the Form1 class adds button1_click as a event handler for Button1 ' s Click event. In the Disconnect method, the event handler is removed.
Using System;
public class Form1:form
{
Public Form1 () {
Add Button1_Click as a event handler for Button1 ' s Click event
Button1.Click + = new EventHandler (button1_click);
}
Button Button1 = New button ();
void Button1_Click (object sender, Event e) {
Console.WriteLine ("Button1 was clicked!");
}
public void Disconnect () {
Button1.Click-= new EventHandler (button1_click);
}
}
The Button class could is rewritten to use a Property-like event declaration rather than a Field-like event declaration. This change has no effect on client code.
public class Button:control
{
Public event EventHandler Click {
get {...}
set {...}
}
public void Reset () {
Click = null;
}
}
1.17 Versioning
Versioning is a after-thought in most languages, but don't in C #.
"Versioning" actually has two different meanings. A new version of a component is ' source compatible ' with a previous version if code this depends on the previous version C A, when recompiled, work with the new version. In contrast, for a "binary compatible" component, a program that depended on the old version can, without recompilation, W Ork with the new version.
Most languages do does not support binary compatibility in all, and many does little to facilitate source compatibility. In fact, some languages contain flaws "make it impossible," "to" evolve a class over time without breaking Me client code.
As a example, consider the situation of a base class author who ships a class named base. In this-version, Base contains no F method. A component named Derived derives from Base, and introduces A F. This Derived class, along with the class Base-it depends on, are released to customers, who deploy to numerous clients and servers.
Author A
Namespace A
{
Class Base//version 1
{
}
}
Author B
Namespace B
{
Class Derived:a.base
{
public virtual void F () {
System.Console.WriteLine ("DERIVED.F");
}
}
}
So far good. But now the versioning trouble begins. The author of Base produces a new version, and adds its own F method.
Author A
Namespace A
{
Class Base//Version 2
{
public virtual void F () {//Added in version 2
System.Console.WriteLine ("Base.F");
}
}
}
This new version of Base should is both source and binary compatible with the initial version. (If it weren ' t possible to simply add a method then a base class could never.) Unfortunately, the new F in Base makes the meaning of Derived ' s f is unclear. Did Derived mean to override Base ' s F? This is seems unlikely, since when Derived is compiled, Base did not even have a F! Further, if Derived ' s F does override Base ' F, then does ' s F Derived to the adhere contract by base? This seems even more unlikely, since it are pretty darn difficult for Derived ' s F to adhere to a contract that didn ' t exist When it is written. For example, the contract of Base's F might require that overrides of it always to call the base. Derived ' s F could not possibly adhere to such a contract since it cannot call a method that does not yet exist.
In practice, would name collisions of this kind actually occur? Let ' s consider the factors involved. The It is important to the authors are working completely independently–possibly in separate corporations– So no collaboration is possible. Second, there may is many derived classes. If There are more derived classes, then name collisions are more likely to occur. Imagine that's base class is Form, and so all VB, VC + + and C # developers are creating derived classes–that ' s a lot o F derived classes. Finally, name collisions are more likely if the base class was in a specific domain, as authors of both a base class and it s derived classes are likely to choose names from this domain.
C # addresses this versioning problem by requiring developers to clearly state their. In the original code example, the code being clear, since Base did not even have a f. Clearly, Derived ' s f is intended as a New method rather than a override of the a base method, since no base method named F exists.
Author A
Namespace A
{
Class Base
{
}
}
Author B
Namespace B
{
Class Derived:a.base
{
public virtual void F () {
System.Console.WriteLine ("DERIVED.F");
}
}
}
If Base adds an F and ships a new version, then the intent of a binary version of Derived are still clear–derived ' s F is Semantically unrelated, and should is treated as an override.
However, when Derived are recompiled, the meaning is unclear–the author of Derived of May intend their F to override Base ' s F, or to hide it. Since The intent is unclear, the C # compiler produces a warning, and by default makes Derived ' s F hide Base ' s F–duplicat ing the semantics for the "case" in which Derived are not recompiled. This warning alerts Derived's author to the presence of the "F method" in Base. If Derived ' s f is semantically unrelated to Base ' F, then Derived ' s author can express this intent–and, in effect, turn Off the warning–by using the New keyword in the declaration of F.
Author A
Namespace A
{
Class Base//Version 2
{
public virtual void F () {//Added in version 2
System.Console.WriteLine ("Base.F");
}
}
}
Author B
Namespace B
{
Class Derived:a.base//Version 2a:new
{
New public virtual void F () {
System.Console.WriteLine ("DERIVED.F");
}
}
}
On the other hand, Derived ' s author might investigate further, and decide that Derived ' s f should override Base ' F, and C Learly Specify this intent through specification of the override keyword, as shown.
Author A
Namespace A
{
Class Base//Version 2
{
public virtual void F () {//Added in version 2
System.Console.WriteLine ("Base.F");
}
}
}
Author B
Namespace B
{
Class Derived:a.base//Version 2b:override
{
public override void F () {
Base. F ();
System.Console.WriteLine ("DERIVED.F");
}
}
}
The author of Derived has one option, and that was to change the name of F, thus completely avoiding the name Collisi On. Though This change would break source and binary compatibility for Derived, the importance of this compatibility varies de Pending on the scenario. If Derived is isn't exposed to other programs, then changing the name of F was likely a good idea, as it would improve the RE Adability of the Program–there would no longer is any confusion about the meaning of F.
1.18 Attributes
C # is a procedural language, but like all procedural languages it does have some declarative. For example, the accessibility of a (a) class is specified by decorating it public, protected, internal, protected Internal, or private. Through its support for attributes, C # generalizes this capability, so that programmers can invent new kinds of declarativ E information, specify this declarative information for various program entities, and retrieve this declarative informatio N at Run-time. Programs Specify this additional declarative information by defining and using attributes.
For instance, a framework might define a HelpAttribute attribute that can is placed on program elements such as classes D methods to provide a mapping from program elements to documentation for them. The example
[AttributeUsage (AttributeTargets.All)]
public class HelpAttribute:System.Attribute
{
Public HelpAttribute (string url) {
This.url = URL;
}
public string Topic = null;
private string URL;
public string Url {
get {return URL;}
}
}
Defines an attributes class named HelpAttribute, or Help for short, that has one positional parameter (string URL) and one Named argument (string Topic). Positional parameters are defined by the formal to parameters for public constructors of the attribute class; Named parameters are defined by public Read-write properties of the attribute class. The square brackets in the example indicate is the use of the "an" in defining's Help attribute. In this case, the AttributeUsage attribute indicates so any program element can is decorated with the help attribute.
The example
[Help ("http://www.mycompany.com/.../Class1.htm")]
public class Class1
{
[Help ("http://www.mycompany.com/.../Class1.htm", Topic = "F")]
public void F () {}
}
Shows several uses of the attribute.
Attribute information for a given program element can be retrieved in Run-time by using the. NET runtime ' s reflection supp Ort. The example
Using System;
Class Test
{
static void Main () {
Type type = typeof (Class1);
object[] arr = type. GetCustomAttributes (typeof (HelpAttribute));
if (arr. Length = = 0)
Console.WriteLine ("Class1 has no help attribute.");
else {
HelpAttribute ha = (HelpAttribute) arr[0];
Console.WriteLine ("URL = {0}, Topic = {1}", ha. Url, ha. TOPIC);
}
}
}
Checks to = If Class1 has a help attribute, and writes out the associated Topic and URL values if the attribute is Prese Nt.
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.