CATEGORII DOCUMENTE |
A property is a member that provides access to a characteristic of 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 be executed when their values are read or written. Properties thus provide a mechanism for associating actions with the reading and writing of an object's attributes; furthermore, they permit such attributes to be computed.
Properties are declared using property-declarations:
property-declaration:
attributesopt
property-modifiersopt
type member-name
property-modifiers:
property-modifier
property-modifiers property-modifier
property-modifier:
new
public
protected
internal
private
static
virtual
sealed
override
abstract
extern
member-name:
identifier
interface-type . identifier
A property-declaration may include a set of attributes (17), a new modifier (10.2.2), an extern modifier (10.6.4), a valid combination of the four access modifiers (10.2.3), and a valid combination of the static (10.5.2), virtual (10.5.3), override (10.5.4), and abstract (10.5.6) modifiers. In addition, a property that includes the override modifier may also include the sealed modifier (10.5.5).
The static, virtual, override, and abstract modifiers are mutually exclusive except in one case. The abstract and override modifiers may be used together so that an abstract property can override a virtual one.
The type of a property declaration specifies the type of the property introduced by the declaration, and the member-name specifies the name of the property. Unless the property is an explicit interface member implementation, the member-name is simply an identifier. For an explicit interface member implementation (13.4.1), the member-name consists of an interface-type followed by a "." and an identifier.
The type of a property must be at least as accessible as the property itself (3.5.4).
The accessor-declarations, which must be enclosed in "" tokens, declare the accessors (10.6.2) of the property. The accessors specify the executable statements associated with reading and writing the property.
Even though the syntax for accessing a property is the same as that for a field, a property is not classified as a variable. Thus, it is not possible to pass a property as a ref or out argument.
When a property declaration includes a static modifier, the property is said to be a static property. When no static modifier is present, the property is said to be an instance property.
A static property is not associated with a specific instance, and it is an error to refer to this in the accessors of a static property. Furthermore, it is an error for a static property to include any of the following modifiers: virtual, abstract, or override.
An instance property is associated with a given instance of a class, and this instance can be accessed as this (7.5.7) in the accessors of the property.
When a property is referenced in a member-access (7.5.4) of the form E.M, if M is a static property, E must denote a type that has a property M, and if M is an instance property, E must denote an instance that has a property M.
The differences between static and instance members are further discussed in 10.2.5.
The accessor-declarations of a property specify the executable statements associated with reading and writing the property.
accessor-declarations:
get-accessor-declaration
set-accessor-declarationopt
set-accessor-declaration
get-accessor-declarationopt
get-accessor-declaration:
attributesopt get accessor-body
set-accessor-declaration:
attributesopt set accessor-body
accessor-body:
block
;
The accessor declarations consist of a get-accessor-declaration, a set-accessor-declaration, or both. Each accessor declaration consists of the token get or set followed by an accessor-body. For abstract and extern properties, the accessor-body for each accessor specified is simply a semicolon. For other properties, the accessor-body for each accessor specified is a block which contains the statements to be executed when the corresponding accessor is invoked.
A get accessor corresponds to a parameterless method with a return value of the property type. Except as the target of an assignment, when a property is referenced in an expression, the get accessor of the property is invoked to compute the value of the property (7.1.1). The body of a get accessor must conform to the rules for value-returning methods described in 10.5.8. In particular, all return statements in the body of a get accessor must specify an expression that is implicitly convertible to the property type. Furthermore, the endpoint of a get accessor must not be reachable.
A set accessor corresponds to a method with a single value parameter of the property type and a void return type. The implicit parameter of a set accessor is always named value. When a property is referenced as the target of an assignment (7.13), or as the operand of ++ or -- (7.5.9,7.6.7), the set accessor is invoked with an argument (whose value is that of the right-hand side of the assignment or the operand of the ++ or -- operator) that provides the new value (7.13.1). The body of a set accessor must conform to the rules for void methods described in 10.5.8. In particular, return statements in the set accessor body are not permitted to specify an expression. Since a set accessor implicitly has a parameter named value, it is an error for a local variable declaration in a set accessor to have that name.
Based on the presence or absence of the get and set accessors, a property is classified as follows:
A property that includes both a get accessor and a set accessor is said to be a read-write property.
A property that has only a get accessor is said to be a read-only property. It is an error for a read-only property to be the target of an assignment.
A property that has only a set accessor is said to be a write-only property. Except as the target of an assignment, it is an error to reference a write-only property in an expression.
In the example
public
class Button: Control
set
}
}
public override void Paint(Graphics g,
Rectangle r)
}
the Button control declares a public Caption property. The get accessor of the Caption property returns the string stored in the private caption field. The set accessor checks if the new value is different from the current value, and if so, it stores the new value and repaints the control. Properties often follow the pattern shown above: The get accessor simply returns a value stored in a private field, and the set accessor modifies the private field and then performs any additional actions required to fully update the state of the object.
Given the Button class above, the following is an example of use of the Caption property:
Button
okButton = new Button();
okButton.Caption = 'OK'; //
Invokes set accessor
string s = okButton.Caption; //
Invokes get accessor
Here, the set accessor is invoked by assigning a value to the property, and the get accessor is invoked by referencing the property in an expression.
The get and set accessors of a property are not distinct members, and it is not possible to declare the accessors of a property separately. As such, it is not possible for the two accessors of a read-write property to have different accessibility. The example
class A
}
public string Name
}
}
does not declare a single read-write property. Rather, it declares two properties with the same name, one read-only and one write-only. Since two members declared in the same class cannot have the same name, the example causes a compile-time error to occur.
When a derived class declares a property by the same name as an inherited property, the derived property hides the inherited property with respect to both reading and writing. In the example
class A
}
}
class B:
A
}
}
the P property in B hides the P property in A with respect to both reading and writing. Thus, in the statements
B b =
new B();
b.P = 1; // Error, B.P is
read-only
((A)b).P = 1; // Ok, reference to A.P
the assignment to b.P causes an error to be reported, since the read-only P property in B hides the write-only P property in A. Note, however, that a cast can be used to access the hidden P property.
Unlike public fields, properties provide a separation between an object's internal state and its public interface. Consider the example:
class
Label
public int X
}
public int Y
}
public Point Location
}
public string Caption
}
}
Here, the Label class uses two int fields, x and y, to store its location. The location is publicly exposed both as an X and a Y property and as a Location property of type Point. If, in a future version of Label, it becomes more convenient to store the location as a Point internally, the change can be made without affecting the public interface of the class:
class
Label
public int X
}
public int Y
}
public Point Location
}
public string Caption
}
}
Had x and y instead been public readonly fields, it would have been impossible to make such a change to the Label class.
Exposing state through properties is not necessarily any less efficient than exposing fields directly. In particular, when a property is non-virtual and contains only a small amount of code, the execution environment may replace calls to accessors with the actual code of the accessors. This process is known as inlining, and it makes property access as efficient as field access, yet preserves the increased flexibility of properties.
Since invoking a get accessor is conceptually equivalent to reading the value of a field, it is considered bad programming style for get accessors to have observable side-effects. In the example
class
Counter
}
}
the value of the Next property depends on the number of times the property has previously been accessed. Thus, accessing the property produces an observable side-effect, and the property should be implemented as a method instead.
The "no side-effects" convention for get accessors doesn't mean that get accessors should always be written to simply return values stored in fields. Indeed, get accessors often compute the value of a property by accessing multiple fields or invoking methods. However, a properly designed get accessor performs no actions that cause observable changes in the state of the object.
Properties can be used to delay initialization of a resource until the moment it is first referenced. For example:
using System.IO;
public
class Console
return reader;
}
}
public static TextWriter Out
return writer;
}
}
public static TextWriter Error
return error;
}
}
}
The Console class contains three properties, In, Out, and Error, that represent the standard input, output, and error devices, respectively. By exposing these members as properties, the Console class can delay their initialization until they are actually used. For example, upon first referencing the Out property, as in
Console.Out.WriteLine('hello, world');
the underlying TextWriter for the output device is created. But if the application makes no reference to the In and Error properties, then no objects are created for those devices.
A property declaration may include a valid combination of the static, virtual, override, and abstract modifiers. A property that includes the override modifier may also include the sealed modifier (10.5.5).
The static, virtual, override, and abstract modifiers are mutually exclusive except in one case. The abstract and override modifiers may be used together so that an abstract property can override a virtual one. A virtual property declaration specifies that the accessors of the property are virtual. The virtual modifier applies to both accessors of a read-write property-it is not possible for only one accessor of a read-write property to be virtual.
An abstract property declaration specifies that the accessors of the property are virtual, but does not provide an actual implementation of the accessors. Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the property. Because an accessor for an abstract property declaration provides no actual implementation, its accessor-body simply consists of a semicolon.
A property declaration that includes both the abstract and override modifiers specifies that the property is abstract and overrides a base property. The accessors of such a property are also abstract.
Abstract property declarations are only permitted in abstract classes (10.1.1.1).The accessors of an inherited virtual property can be overridden in a derived class by including a property declaration that specifies an override directive. This is known as an overriding property declaration. An overriding property declaration does not declare a new property. Instead, it simply specializes the implementations of the accessors of an existing virtual property.
An overriding property declaration must specify the exact same accessibility modifiers, type, and name as the inherited property. If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property must include only that accessor. If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors.
An overriding property declaration may include the sealed modifier. Use of this modifier prevents a derived class from further overriding the property. The accessors of a sealed property are also sealed. It is an error for an overriding property declaration to include a new modifier.
Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. Specifically, the rules described in 10.5.3, 10.5.4, 10.5.5, and 10.5.6 apply as if accessors were methods of a corresponding form:
A get accessor corresponds to a parameterless method with a return value of the property type and the same modifiers as the containing property.
A set accessor corresponds to a method with a single value parameter of the property type, a void return type, and the same modifiers as the containing property.
In the example
abstract
class A
}
public virtual int Y
set
}
public abstract int Z
}
X is a virtual read-only property, Y is a virtual read-write property, and Z is an abstract read-write property. Because Z is abstract, the containing class A must also be declared abstract.
A class that derives from A is show below:
class B:
A
}
public override int Y
}
public override int Z
set
}
}
Here, the declarations of X, Y, and Z are overriding property declarations. Each property declaration exactly matches the accessibility modifiers, type, and name of the corresponding inherited property. The get accessor of X and the set accessor of Y use the base keyword to access the inherited accessors. The declaration of Z overrides both abstract accessors-thus, there are no outstanding abstract function members in B, and B is permitted to be a non-abstract class.
When a property declaration includes an extern modifier, the property is said to be an external property. Like external methods (10.5.7), external properties are implemented externally, using a language other than C#. Because an external property declaration provides no actual implementation, each of the accessor-declarations of a property consists of a semicolon.
It is an error for an external property declaration to also include the abstract modifier. When an external property includes a DllImport attribute, the property declaration must also include a static modifier.
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 978
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved