Appendix K
Classes and Structures

This appendix provides information about class and structure declarations.

Classes

The syntax for declaring a class follows.

«attributes» «accessibility» «abstract|sealed|static» «partial»
    class name «inheritance»
{
    statements
}

The following list describes the declaration’s pieces.

  • attributes—This can include any number of attribute specifiers.
  • accessibility—This can be one of public, internal, private, protected, or protected internal.
  • abstract—This keyword means you cannot create instances of the class. Instead you can make instances of derived classes.
  • sealed—This keyword means you cannot derive other classes from the class.
  • static—This keyword means you cannot derive other classes from the class or create instances of it. You invoke the members of a static class by using the class’s name instead of an instance. All members of a static class must also be declared static.
  • partial—This keyword indicates that this is only part of the class declaration and that the program may include other partial declarations for this class.
  • name—This is the name you want to give the class.
  • inheritance—This clause can include a parent class, one or more interfaces, or both a parent class and interfaces. If the declaration includes a parent class and interfaces, the parent class must come first.

Structures

The syntax for writing a structure follows.

«attributes» «accessibility» «partial» struct name «interfaces»
{
    statements
}

The structure’s attributes, accessibility, and partial clauses are the same as those for classes. See the previous section for details.

Structures cannot inherit, so they cannot have inheritance clauses. Instead they have interfaces clauses that specify any interfaces the structure implements.

Following are the major differences between a structure and a class.

  • Structures cannot inherit.
  • Structures cannot use the abstract, sealed, or static keywords because you cannot inherit from a structure.
  • Structures are value types, whereas classes are reference types. See the section “Value Versus Reference Types” in Chapter 12, “Classes and Structures,” for information on the consequences of this difference.

Constructors

A constructor is a special method that has no name and that returns the type of the class or structure that contains it. Alternatively, you can think of a constructor as having the same name as its class and returning no type, not even void.

Class constructors can take any number of parameters. If you provide no constructors, C# creates a default parameterless constructor that takes no parameters. If you provide any constructor, C# does not provide a default parameterless constructor. If you want to allow the program to use a parameterless constructor in that case, you must either provide one or provide a constructor with all optional parameters.

Structure constructors are similar to class constructors with two major exceptions. First, you cannot make a structure constructor that takes no parameters. Second, C# always provides a default parameterless constructor, even if you give the structure other constructors.

Destructors

A destructor is a method that executes when an object is destroyed. Before it permanently destroys an object, the garbage collector calls that object’s destructor so that the destructor can clean up unmanaged resources. Keep in mind that finalization is nondeterministic, so you generally don’t know when the destructor will be called.

To create a destructor, create a method named after the class with a ~ character in front of it. For example, the following code shows a destructor for the Person class.

~Person()
{
    // Free unmanaged resources here.
    ...
}

To allow a program to free resources before an object is destroyed, you can give the class a Dispose method and implement the IDisposable interface.

The following list summarizes the key destruction issues.

  • The destructor is called automatically when an object is destroyed.
  • The destructor cannot refer to managed objects because they may have already been destroyed. In particular, the destructor cannot free managed resources because they may have already been destroyed.
  • The destructor must free unmanaged resources. This is the last chance the object has for freeing those resources.
  • Instead of making the program wait an unknowable amount of time for the destructor to execute, you can provide a Dispose method that disposes of all resources when the object is done with them.
  • If you implement the IDisposable interface, the using statement calls Dispose automatically.
  • Either it must be safe for the Dispose method and the destructor to both run, or you can ensure that they both can’t run by making the Dispose method call GC.SuppressFinalize.

Events

An event lets an object notify the application that something potentially interesting has occurred.

Following is the syntax for declaring an event.

«attributes» «accessibility» «new|virtual|override|abstract|sealed» «static»
    event delegate name;

The following list describes the declaration’s pieces.

  • attributes—Attributes provide extra information about the event for use by the compiler, the runtime system, and other tools.
  • accessibility—This can be public, private, protected, internal, or protected internal and is similar to the accessibility for other items such as classes, properties, and methods.
  • new|virtual|override|abstract|sealed—These are similar to the keywords used by methods described in Chapter 6, “Methods.” They have the following meanings:
    • new—Hides an event with the same name defined in an ancestor class.
    • virtual—If you mark an event as virtual, you can later replace it in a derived class by overriding it.
    • override—If an ancestor class defines a virtual event, you can use the override keyword to override it.
    • abstract—This keyword indicates the event is abstract, so derived classes must override the event to give it an implementation. As is the case with abstract methods, a class that contains an abstract event must be abstract and cannot be instantiated.
    • sealed—This keyword indicates the event is no longer virtual, so it cannot be overridden in derived classes.
  • static—This indicates the class itself raises the event rather than instances of the class.
  • delegate—This is a delegate type that defines the parameters that will be passed to event handlers for the event.
  • name—This is the name you want to give the event.

To raise an event, first determine whether any other pieces of code have registered to receive the event by comparing the event to null. If code has registered to receive the event, invoke the event by name, passing it any necessary parameters.

For example, suppose the Student class has a GradeChanged event. Then the following snippet inside the Student class raises the event, passing it the current Student object as a parameter.

if (GradeChanged != null) GradeChanged(this);

To subscribe to an event, use the += operator to “add” the event handler to the event. The following code shows how a program could register the MyPerson_NameChanged event handler to handle the MyPerson object’s NameChanged event.

MyPerson.NameChanged += MyPerson_NameChanged;

If you subscribe an event handler to an event multiple times, it executes multiple times when the event occurs.

To unsubscribe from an event, use the -= operator, as in the following code.

MyPerson.NameChanged -= MyPerson_NameChanged;

Unsubscribing from an event more times than the event handler was originally registered does not throw an exception.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.32.154