".NET Program Pioneer C #" Chapter 5 Class Christoph Wille | 2001-9-1
The first chapter of Chapter 5 discusses data types and their usage. Now we move to C #, which is crucial - class. Without a class, even simple C # programs cannot be compiled. This chapter assumes that you know the basic components of a class: method, attribute, configuration function, and destructor. C # has increasing indexes and events. In this chapter, you learned the topic of the following classes. . Use constructor and destructor. Write a way for a class. Give a class to add attribute access flags. Implement index. Create an event and associate with the event by representative. Apply, members, and access modifiers. 5.1 Constructor and Destructor Functions You can access a class method, attribute, or any other thing, the first executed statement is a constructor containing a corresponding class. Even you don't write a constructor, there will be a default constructor to provide you. Class testclass (): base () {} // provides a constructor to be the same as the class name of the compiler, but it does not declare the return type. In short, the constructor is always public, you can use them to initialize the variable. Public TestClass () {// This gives a variable // initialization code, etc. } If the class contains only static members (can be called by type, instead of instance calls), you can create a private constructor. Private testclass () {} Although the access modifier is discussed in this chapter, Private means that it is impossible to access the constructor from the outside of the class. So, it cannot be called, and there is no object to be instantiated from this class definition. Not limited to the parametric constructor - you can pass the initial parameters to initialize the member. Public TestClass (String Strname, Int Nage) {...} As a C / C programmer, you may be accustomed to writing an additional method for initialization because there is no return value in the constructor. Of course, although there is no return value in C #, you can trigger a homemade exception to get the return value from the constructor. More knowledge about exception handling is discussed in Chapter 7 "Abnormal Processing". However, when you reserve reference to valuable resources, you should think of a way to resolve: A way to be explicitly adjusted to release these resources. The problem is when you can do the same thing in the destructor (named "~" in front of the name of the name). PPUBLIC ~ TESTCLASS () {// Clear} you The reason why an additional method should be written is the garbage collector, which is not immediately called after the variable is out of range, but is only triggered when the intermittent period or memory condition is satisfied. When you lock the resource longer than the time you plan, it will happen. Therefore, providing an explicit release method is a good idea, which can also be called from the destructor. Public void release () {// Releases all valuable resources} public ~ testclass () {Release ();} The release method in the call destructor is not necessary - in short, the garbage collection will pay attention to the release of the object. But there is no forgetting clearing is a good habit. 5.2 Method Since the object can initialize and end correctly, the remaining is to increase the function in category. In most cases, the main part of the function can be achieved in the method. You have already seen the use of static methods, however, these are parts of type (class), not examples (objects). In order for you to get started quickly, I arranged these methods of cumbersome problems as three:. Method parameters. Rewriting method. Method Shield 5.2.1 Method Parameters Because Method To process change value, you have less than to transfer values to the method, and get return values from the method. The following three parts relate to problems caused by the transfer value and the returning result of the caller. . Input parameters. Quote parameters. Output parameter 5.2.1.1 Enter parameters You have already seen a parameter you have seen in the example is the input parameter.
You use an input parameter to pass a value via a value to a method for a variable that is transferred by the caller being transferred in the value of the value passed. Listing 5.1 Demonstration of input parameters. Listing 5.1 Transfer parameters by values 1: use system; 2: 3: public class squaresample4: {5: public int Calcsquare (int nsideLength) 6: {7: return nsidength * nsideLength; 8:} 9:} 10: 11: Class Squareapp12: {13: public static void main () 14: {15: SquareSample SQ = new SquareSample (); 16: console.writeline (sq.calcsquare (25) .tostring ()); 17:} 18:} The transfer value is not referenced to a variable, so a constant expression (25) can be used when the method is called (see Chapter 16). The integer result is transmitted to the caller as the return value, which is displayed immediately on the screen without the intermediate variable. Enter parameters work in a working mode that C / C programmers have been habits. If you are from VB, please pay attention to the implicit BYVAL or BYREF that can be processed by the compiler, if not set, the parameter always passes. This seems to have conflicts with me in front: For some variable types, the value transfer actually means that the reference is passed. Confusion? Little background knowledge does not need: COM is the interface, each class can have one or more interfaces. An interface is just a set of function pointers, which does not contain data. Repeating the array will waste a lot of memory resources; so only the start address is copied to the method, which is the same pointer to the interface as the caller. That is why the object uses a value to pass a reference. 5.2.1.2 Reference Parameters Although many methods can be established using input parameters and return values, you think that you want to transfer values and modify it in place (that is, in the same memory location), it is not so good luck. It is very convenient to use the reference parameters here. Void MyMethod (Ref Int Ninout) Because you pass a variable to this method (not just its value), the variable must be initialized. Otherwise, the compiler will alarm. Listing 5.2 Display how to create a method with a reference parameter. Listing 5.2 Parameters 1: // Class Squaresample2: Using System; 3: 4: Public Class Squaresample5: {8: None4all * = None4all; 9: None4all * = none4all; 9:} 10: } 11: 12: Class Squareapp13: {14: public static void main () 15: {16: SquareSample (); 17: 18: int nsquardref = 20; // must initialize 19: sq.calcsquare Ref nsquardref; 20: console.writeline (nsquardref.tostring ()); 21:} 22:} As seen, all you have to do is adding the REF qualifier to definition and calls. Because variables are passed by reference, you can use it to calculate the results and pass the result. However, in a realistic application, I strongly recommend using two variables, an input parameter, and a reference parameter. 5.2.1.3 The third selection of the output parameter transmission parameters is to set it as an output parameter. As the name is implicit, an output parameter is only used to pass back from the method back to a result. Another difference between it and the reference parameters is that the caller does not have to initialize the variable to call the method. This is shown in Listing 5.3.
Listing 5.3 Define an output parameter 1: use system; 2: 3: public class squaresample4: {5: public void calcsquare (int nsideLength, out int nsquared) 6: {7: nsquared = nsideLength * nsideLength; 8:} 9:} 10: 11: Class Squareapp12: {13: public static void main () 14: {15: SquareSample SQ = new SquareSample (); 16: 17: int nsquared; // does not have to initialize 18: sq.calcsquare (15, out nsquared 19: console.writeline (nsquared.tostring ()); 20:} 21:} 5.2.2 Important principles of object-oriented design is polymorphism. Don't pay attention to a deep theory, a polymorphism means that when the base class programmer has designed a method for rewriting, in the derived class, you can redefine (rewritten) the method of the base class. Base class programmer can use virtual keyword design method: virtual void canboverridden () When you derive from the base class, all you have to do is adding Override keywords in a new method: Override void canboverridden () When rewriting a base class When the method, you must understand that you can't change the access properties of the method - behind this chapter, you will learn more about accessing the modifier. In addition to rewriting the basic class method, there is another or more important rewriting feature. When the derived class is forced to convert into a base type and then call the virtual method, the method called the derived class is not a method of the base class. (BASECLASS) DerivedClassInstance) .canboverridden (); To demonstrate the concept of a virtual method, Listing 5.4 shows how to create a triangular base class, which has a member method that can be rewritten (ComputeArea). Listing 5.4 Removing a base class method 1: use system; 2: 3: Class Triangle4: {5: Public Virtual Double ComputeArea (int A, int b, int C) 6: {7: // Heronian Formula8: double s = (A B C) / 2.0; 9: Double Darea = Math.SQRT (S * (SA) * (SB) * (SC)); 10: Return Darea; 11:} 12:} 13: 14: Class Rightangle15: {16: Public Override Double ComputeArea (int A, int b, int c) 17: {18: Double Darea = a * b / 2.0; 19: Return Darea; 20:} 21:} 22: 23: Class triangletestapp24: {25: public static void main () 26: {27: triangle tri = new triangle (); 28: console.writeline (Tri.ComputeArea (2, 5, 6)); 29:30: RightangledTriangle Rat = New rightangledtriangle (); 31: console.writeline (Rat.comPuterea (3, 4, 5)); 32:} 33:} The base class Triangle defines the method ComputeArea.
It uses three parameters to return a Double result and have public accessibility. From the Triangle class, RightangledTriangle, rewritten the ComputeArea method and implemented its own area calculation formula. Both classes are instantiated and verified in the main () method of the application class named TriangleTestApp. I missed the 14th line: Class RightangledTriangle: Triangle's colon (:) in the class statement is represented by RightangleDTriangle. That is what you have to do, so that C # knows you want to treat Triangle as the base class of RightangledTriangle. When you carefully observe the COMPUTEAREA method of the right angle triangle, you will find that the third parameter is not used to calculate. However, using this parameter can verify that it is "right angle". As shown in Listing 5.5. Listing 5.5 Calling the base class implementation 1: Class RightangledTriangle: Triangle2: {3: Public Override Double ComputeArea (int A, int B, int C) 4: {5: const double defsilon = 0.0001; 6: double darea = 0; 7: IF (Math.abs ((A * A B * B - C * C)> Depsilon) 8: {9: Darea = Base.computeArea (A, B, C); 10:} 11: Else12: {13 : Darea = a * b / 2.0; 14:} 15: 16: Return Darea; 17:} 18:} This test simply utilizes the Pydalas formula, for the right triangle, the detection result must be 0. If the result is not 0, the class calls the COMPUTEAREA of its base class. Darea = base.computeArea (A, B, C); the main point of example is: By explicitly use the qualification examination of the base class, you can easily call the base class to implement the rewritable method. This is very helpful when you need to implement its features in the base class, but don't want to repeat it in the rewrite method. 5.2.3 Method The method of shielding the definition method is a method to shield the base class. This feature special value when derived from the class provided by others. Look at Listing 5.6, assuming that BaseClass is written by others, and you derive DeriveDclass from it. Listing 5.6 Derived Class implementation a method not included in Base Class 1: USING SYSTEM; 2: 3: Class Baseclass4: {5:} 6: 7: Class DerivedClass: Baseclass8: {9: Public void testMethod () 10: { 11: console.writeline ("derivedclass :: testmeth); 12:} 13:} 14: 15: Class testapp16: {17: public static void main () 18: {19: derivedclass test = new derivedclass (); 20 : Test.TestMethod (); 21:} 22:} In this example, DeriveDClass implemented an additional function through TestMethod ().
However, if the developer of the base class believes that the testMethod () is a good idea in the base class, and what is the problem when using the same name to implement it? (See Listing 5.7) Listing 5.7 Base Class Implementation and Derived Class 1: Class Baseclass2: {3: Public Void TestMethod () 4: {5: Console.Writeline ("Baseclass :: TestMethod"); 6:} 7 :} 8: 9: Class DerivedClass: Baseclass10: {11: Public void testMethod () 12: {13: console.writeline ("derivedclass :: testhod"); 14:} 15:} In excellent programming language, you I will now encounter a real big trouble. However, C # will give you a warning: hiding2.cs (13,14): warning CS0114:. 'DerivedClass.TestMethod ()' hides inherited member 'BaseClass.TestMethod ()' To make the current method override that implementation, add the Other Keyword. Otherwise add the new keyword. (13,14): Warning CS0114: 'DerivedClass.TestMethod () shields the successful member' baseclass.testMethod () '. To make the current method to overwrite the original Implementation, add an Override keyword. Otherwise, add a new keyword.) Has a modifier new, you can tell the compiler, do not have to rewrite the derived class or change the code to derive class, your method can Shield the newly added base class method. Listing 5.8 Display how to use New modifiers in an example. Listing 5.8 Shielding Basic Type Method 1: Class BaseClass2: {3: Public Void TestMethod () 4: {5: Console.writeline ("Baseclass :: TestMethod"); 6:} 7:} 8: 9: Class DerivedClass: baseclass10 : {11: New public void testMethod () 12: {13: console.writeline ("derivedclass :: testmeth"); 14:} 15:} Used additional new modifiers, the compiler knows that you will define the base The method of the class, it should be shielded by the base class. However, if you are written as follows: DerivedClass test = new derivedclass (); (BASECLASS) TEST) .TestMethod (); the implementation of the base class method is called. This behavior is different from the rewriting method, and the latter guarantees that most derived methods are called. 5.3 Class properties There are two ways to discover the naming properties of the class - through the domain member or by attribute. The former is implemented as a member variable with public access; the latter does not respond directly to the storage location, just accessible by access logo (Accessors). When you want to read or write the value of the property, the access flag limits the statement implemented. The access flag for reading the value of the attribute is a keyword GET, and the read and write error flag to modify the value of the property is SET. Before you know the theory, please take a look at the example in Listing 5.9, the attribute SquareFeet is marked with GET and SET access flags.
Listing 5.9 Implementing Properties Acquisition Sign 1: Using System; 2: 3: Public Class House4: {5: Private INT M_NSQFEET; 6: 7: PUBLIC INT SQUAREFEET8: {9: Get {Return M_NSqFeet;} 10: set {m_nsqfeet = Value;} 11:} 12:} 13: 14: Class testapp15: {16: public static void main () 17: {18: house myhouse = new house (); 19: myhouse.squarefeet = 250; 20: console. WriteLine (myhouse.squarefee); 21:} 22:} The House class has a property named SquareFeet, which can be read and written. The actual value is stored in a variable that can be accessed from the class - if you want to turn it as a domain member, you have to do it is to ignore the access flag and redefine the variable as: public int squarefee; for one Such a simple variable, this is not bad. However, if you want to hide the details of the internal storage structure, you should use the access flag. In this case, the SET access flag delivers a new value in the attribute in the value parameter. (You can change the name, see Eight lines.) In addition to hiding the implementation details: GET and SET: Allow read and write access to the attribute. GET ONLY: Only the value of the read attribute is allowed. SET ONLY: Only the value of the write attribute is allowed. In addition, you can get an opportunity to achieve valid code in the set flag. For example, you can reject a new value due to various reasons (or if there is no reason). It is best to tell you that it is a dynamic attribute - when you ask it, it will save it, so you can postpone resource allocation as much as possible. 5.4 Index Do you want to use an index accessed class like an array? Using the C # index function, it can be knotted. The syntax is basically like this: the property modifier declares {Declaration content} Specific example for public string this [int NINDEX] {GET {...} set {...}} index returns or pressed the index setting string . It doesn't have attributes but uses a public modifier. The declaration part is used by type String and this composition for representation of the index of the class. Get and set execution rules and properties are the same. (You can't cancel one.) There is only one difference, that is, you can almost arbitrarily define parameters in the burous arc. Restrictions, at least one parameter must be specified, allowing REF and OUT modifiers. This keyword ensures an explanation. Index No user-defined name, this represents the index of the default interface. If the class implements multiple interfaces, you can add more indexes description by InterfaceName.THIS. To demonstrate an index, I created a small class that can resolve a host name IP address - or an IP address list (take http://www.microsoft.com as an example). This list can be accessed by indexing, you can take a look at the specific implementation of the list 5.10.
Listing 5.10 Get an IP address 1: use system.net; 3: 4: ipaddress [] m_ARrips; 7: 8: public void resolve (string strhost) 9: {String strHost 9: {STRING STRHOST 9: { 10: iphostentry iphe = dns.gethostbyname (strHost); 11: m_arrips = iphe.addressList; 12:} 13: 14: public ipaddress this [int NINDEX] 15: {16: get17: {18: return m_ARrips [NINDEX]; 19:} 20:} 21: 22: Public Int count23: {24: get {return m_arrips.Length;} 25:} 26:} 27: 28: Class DnsResolVerapp29: {30: public static void main () 31: { 32: resolvedns mydnsresolver = new resolvedns (); 33: mydnsResolver.resolve ("http://www.microsoft.com"); 34: 35: Int ncount = mydnsResolver.count; 36: console.writeline ("Found {0 } Ip's for hostname ", ncount); 37: for (int i = 0; i Since I have mentioned all the functions of the event and the corresponding representative meta, please see the example in Listing 5.11. It vividly reflects the theory. Listing 5.11 Implementing event processing in the class: Using system; 2: 3: // Declaration 4: Public Delegate Void EventHandler (String Strtext); 5: 6: Class EventSource7: {8: Public EventHandHandLer Textout; 9: 10: Public void Triggerevent () 11: {12: if (Null! = Textout) Textout ("Event Triggered"); 13:} 14:} 15: 16: Class TestApp17: {18: Public Static Void Main () 19 : {20: EventSource evtingrc = new eventsource (); 21: 22: evtingrc.textout = new eventHandler (CatChevent); 23: evtsrc.triggerevent (); 24: 25: evtingrc.textout - = new eventhandler (catchst); 26: evtingrc.triggerevent (); 27: 28: Testapp theapp = new testApp (); 29: evtingrc.textout = new eventhandler (THEAPP.INSTANCATCH); 30: evtsrc.triggerevent (); 31:} 32: 33: public static void CatchEvent (string strText) 34: {35: Console.WriteLine (strText); 36:} 37: 38: public void InstanceCatch (string strText) 39: {40: Console.WriteLine ( "Instance" strText); 41:} 42:} The fourth line declares that the representative dollar (original), it is used to give a member of the EventSource class declaration Textout event domain. You can observe that the representative is a new type declaration that can be used as a representative element when declaring events. This class has only one way, which allows us to trigger events. Please note that you must conduct event domain members not detection of NULL, as there may be no customer interest in this situation. The TestApp class contains the main method, as well as the other two methods, which have the signals necessary for events. One of the methods is static, and the other is an example method. EventSource is instantiated, and the static method CatChevent is preustomed to the TEXTOUT event: evtingrc.textout = new eventhandler (CatChevent); from now, the method is called when the event is triggered. If you are not interested in events, simply cancel the association: evsrc.textout - = new eventhandler (CatChevent); Note that you cannot cancel the associated processing function - only these processing functions are created in class code. In order to prove that the event handler is also working with the instance method, the remaining code establishes the example of TestApp, and hooks the event processing method. Where is the event is particularly useful? You will often involve events and representatives often in ASP or in WFC (Windows Foundation Classes). 5.5 Application Modifiers In this chapter, you have seen modifiers such as public, Virtual. I want to summarize them with an easy-to-understand method, I divide them into three quarters:. Class modifier. Member modifier. Access modifier 5.5.1 Class modifier so far, I have not involved in class modifiers, but only involve access modifiers applied to classes. However, there are two modifiers you can use for classes: Abstract - Abstract to abstract classes is that it cannot be instantiated. Only not abstract derived classes can be instantiated. Detective classes must implement all abstract members of the abstract base class. You can't use Sealed modifiers to abstract classes. Sealed - the seal cannot be inherited. Use this modifier to prevent accidental inheritance, use this modifier in the .NET frame. To see the use of two modifiers, look at Listing 5.12, which created a sealing class based on an abstract class (definitely a very extreme example). Listing 5.12 abstract classes and sealing Class 1: using System; 2: 3: abstract class AbstractClass4: {5: abstract public void MyMethod (); 6:} 7: 8: sealed class DerivedClass: AbstractClass9: {10: public override void MyMethod () 11: {12: console.writeline ("Sealed Class"); 13:} 14:} 15: 16: Public class testapp17: {18: public static void main () 19: {20: derivedclass dc = new derivedclass (); 21: dc.mymethod (); 22:} 23:} 5.5.2 Member modifiers Compared with the useful member modifiers, there are few quantities. I have mentioned some, this book is about to appear an example of other member modifiers. The following is a useful member modifier: Abstract - Description A method or access flag does not contain an implementation. They are all implicit virtuals, and in the inheritance class, you must provide Override keywords. Const - This modifier is applied to domain members or local variables. The time-translational constant expression is evaluated, so it cannot contain a reference to the variable. Event - Defines a domain member or attribute as a type event. Events used to bundle customer code to classes. Extern - tells the compiler method to actually be implemented by external implementation. Chapter 10, "And non-accomplished code" will fully involve external code. Override - Methods and access flags used to rewrite any base class are defined as Virtual. The names and base classes to be rewritten must be consistent. READOONLY - A domain member using the Readonly modifier can only be changed in its declaration or in a constructor containing its class. Static - member that is declared as static is a class, not an instance of a class. You can use static to domain members, methods, properties, operators, even constructor. Virtual - Description Method or Access flag can be rewritten by inheritance. 5.5.3 Acquisition modifier depot decoration defines the access level of some code to class members such as methods and properties. You must add a desired access modifier to each member, otherwise the default access type is implied. You can apply one of 4 access modifiers: public - anywhere can access the member, which is a minimum restricted access modifier. Protected - You can access the member in class and all derived classes, and external access is not allowed. Private - only within the same class can access the member. Even derived classes cannot access it. INTERNAL - Allows all code access to the same component (application or library). At the .NET component level, you can treat it as public, while the outside is Private. In order to demonstrate the usage of the exemption, I have modified Triangle examples, enabling it a new domain member and a new derive class (see Listing 5.13). Listing 5.13 Using access modifiers 1: use system; 2: 3: Internal class triangle4: {5: protected int m_a, m_b, m_c; 6: Public Triangle (int A, Int B, INT C) 7: {8: m_a = a; 9: m_b = b; 10: m_c = C; 11:} 12: 13: Public Virtual Double Area () 14: {15: // Heronian Formula16: double s = (m_a m_b M_c) / 2.0; 17: Double Darea = Math.SQRT (S * (S-m_A) * (S-M_B) * (S-M_C)); 18: Return Darea; 19:} 20:} 21: 22: INTERNAL CLASS Prism: Triangle23: {24: Private Int M_H; 25: Public Prism (Int A, Int B, INT C, INT H): Base (A, B, C) 26: {27: M_H = H; 28: } 29: 30: Public override double area () 31: {32: double darea = base.area () * 2.0; 33: Darea = m_a * m_h m_b * m_h m_c * m_h; 34: Return Darea; 35 :} 36:} 37: 38: Class Prismapp39: {40: public static void main () 41: {42: Prism Prism = New Prism (2, 5, 6, 1); 43: Console.WriteLine (Prism.area ()); 44:} 45:} Triangle class and PRISM class are now marked in INTERNAL. This means they can only be accessed in the current component. Keep in mind that the term ".NET component" refers to packaging (packaging,) instead of the components you might be used in COM . Triangle classes have three protected members that are initialized in the constructor and are used in the method of area calculation. Since these members are protected members, I can access them in derived PRISM, where different area calculations are performed. Prism has added a member M_H, which is private - or even derived classes cannot access it. It is often a good idea for each class member or even each class. When you need to introduce modifications, a comprehensive plan will eventually help you, because there is no programmer that is willing to use the "No Document" class feature. 5.6 Summary This chapter shows various elements of the class, which is a template for running an example (object). The code first executed is a constructor in the lifetime of an object. The constructor is used to initialize the variable, which later used in the method to calculate the results. Method allows you to transfer values, reference to variables, or only one output value. Methods can be rewritten to implement new features, or you can block base classes, if it implements the same name with the derived class member. Naming properties can be implemented as domain members (member variables) or attribute access flags. The latter is GET and SET access flags, ignore one or another, you can create only write or read properties. The access flag is well suited to confirm the value assigned to the property. Another feature of the C # class is an index, which is possible to enable the like-by-array syntax.