Top Ten Traps In C # for C Programmers Chinese Edition
Author: Jesse Liberty
Translator: glory
[Interportion: C # get started with the article. Please note: All program debugging environments are Microsoft Visual Studio.NET 7.0 Beta2 and Microsoft .NET Framework SDK Beta2. Limited to translator's time and ability, if there is a mistake in the text, when the original version is prevail]
Trap 6. The virtual method must be explicitly overloaded
In C #, if the programmer decides to overload a virtual method, he (she) must explicitly use the Override keyword.
Let us examine this benefits. Suppose the company A wrote a Window class, company B purchased a copy of the company A's Window class as a base class. The programmers of the company B are derived. [Translation: Original is ... Using ..., from below, it is obviously "derived". In fact, there is also a "combination" in the way (also "embedded" or "inclusive" (COM semantics), etc.), and the latter does not exist as the problem described below] Listbox and Radiobutton classes. The programmer of company B does not know or cannot control the design of the WINDOW class, including the company A will be modified to the Window class.
Now, suppose the programmer of company B decided to join a Sort method for Listbox:
Public Class Listbox: WINDOW
{
Public virtual void sort () {"}
}
This is no problem - until the company's Window author released a Window class version 2, company A programmers joined a PUBLIC's Sort method to the Window class:
Public Class Window, PUBLIC CLASS WINDOW
{
// "
Public virtual void sort () {"}
}
In C , the new virtual method of the Window class will work as a base class for the ListBox virtual method. When you try to call the WINDOW SORT, it is actually called the listBox's sort. C # Medium Method [Translation: Original Writing Virtual Function] is always considered a virtual scheduled root. That is to say, as long as the C # finds a virtual method, it will not be further found along the inheritance level. If a new Sort is introduced into Window, the runtime behavior of Listbox will not be changed. When Listbox is compiled again, the compiler will make a warning:
"/class1.cs (54, 24): Warning CS0114: 'listbox.sort ()' hides inherited member 'window.sort ()'.
If you want to reload the current member, you can add the Override keyword. Otherwise, add the new keyword.
If you want to remove this warning, the programmer must clearly indicate his intentions. You can specify the ListBox's Sort method to NEW to indicate that it is not an overloaded of the virtual method for Window:
Public Class Listbox: WINDOW
{
Public New Virtual Void Sort () {"}
This will not warn again if the compiler will. On the other hand, if the programmer wants to overload the WINDOW method, as long as the Override keyword is explicitly.
Trap seven: Cannot initialize at the head
Initialization in C # is different from C . Assume that you have a class Person, it has a private member variable AGE; a derived class Employee, which has a private member variable SalaryleverL. In C , you can initialize the list part in the member of the Employee constructor to initialize Salarylevel: Employee :: Employee (int theage, int thesalarylevel):
Person (Theage) // Initialization Base
Salarylevel (THSALYLEVEL) // Initialization member variable
{
// Treatment device
}
In C #, this constructor is illegal. Although you can still initialize the basis such that the initialization of the member variable will result in a compile time error. Of course, you can assign the initial value at the member variable statement:
Class Employee: Public Person
{
// Declaration here
Private Salarylevel = 3; // Initialization
}
[Translation: The above code is incorrect LC #, correctly written as follows:
Class Employee: Person
{
Private Int Salarylevel = 3;
}
】
Note: You don't need to add a semicolon after every class declaration, each member must have an explicit access level statement.
Trap 8. Cannot convert Boolean values to integer values
In C #, the Booler (FALSE) is different from the integer value. So can't write this:
IF (SomefuncWhichreturnsavalue ()) // [Translation: Suppose this method does not return Boolean]
You can't expect if someFuncWhichreturnsavalue returns one 0 it will be equal to FALSE, otherwise TRUE. A good news is that old falsis that is misuse the assignment operator rather than the equal operator will not be committed again. So if you write this:
IF (x = 5)
A compile error will be obtained because the result of x = 5 is 5, and it is not a Boolean value.
[Translation: The following is a logical error that will not be careful in C . The compiler will not have any prompts L. It is very smooth, but the result is not what you want:
C :
#include "stdafx.h"
Int main (int Argc, char * argv [])
{
INT n = 0;
IF (n = 1) // The compiler does not say that L is recommended to write to 1 == n, in case 1 = n compiler, do not agree J
{
Printf ("1 / n");
}
Else
{
Printf ("0 / n");
}
Return 0;
}
The above operation results are 1, which is not necessarily what you want.
C #:
Using system;
Public Class RytestBoolapp
{
Public static void main ()
{
INT n = 0;
IF (n = 1) // The compiler does not agree that J cannot convert int to BOOL
{
Console.WriteLine ("1");
}
Else
{
Console.writeLine ("0");
}
}
}
However, if this is this:
BOOL B = false;
IF (b = true)
...
No matter whether it is C or C #, it doesn't.
】
[Translation] C programmers generally like this free way: if (MyRef)
IF (Myint)
But in C #, you must write:
IF (myRef == null) // or if (null == myref)
IF (Myint == 0) // or if (0 == MyInt)
Wait.
】
Trap nine.switch statement will not "run through"
In C #, the CASE statement does not run through the next sentence - if there is code in this case. Therefore, although the following code is legal in C , it is not in C #.
Switch (i)
{
Case 4:
Callfuncone ();
Case 5: // Error, can not run through
Callsomefunc ();
}
In order to achieve this, you need to explicitly use the GOTO statement:
Switch (i)
{
Case 4:
Callfuncone ();
Goto Case 5;
Case 5:
Callsomefunc ();
}
If the CASE statement does not do anything (there is no code inside), you can run through:
Switch (i)
{
Case 4: // can run through
Case 5: // can run through
Case 6:
Callsomefunc ();
}
[Translation: The following is a complete example using Switch, which also illustrates the type of Switch statement domain to be a string and demonstrates how the properties are used.
Using system;
Class Ryswitchtest
{
Public RyswitchTest (String Astr)
{
THIS.STRPROPERTY = astr;
}
Protected string strong;
Public String Stropy
{
get
{
Return this.strfield;
}
set
{
THIS.STRFIELD = VALUE;
}
}
Public void switchtrproperty ()
{
Switch (this.strproperty)
{
Case ("ry01"):
Console.writeline ("ry01");
Break;
CASE ("ry02"):
Console.writeLine ("ry02");
Break; // If this line comes out, the compiler will report to another label from a CASE tab (CASE "ly02" :), if you do need, you can write: goto case ("ry03); Or Goto Default.
Case ("RY03"):
Console.writeline ("ry03");
Break;
DEFAULT:
Console.writeline ("default");
Break;
}
}
}
Class RyswitchTestApp
{
Public static void main ()
{
Ryswitchtest RST = New RyswitchTest ("ry02");
Rst.SwitchStrProperty ();
}
}
】
Trap ten.c # Need a clear assignment operation
The C # requires a clear assignment operation, which means that all variables must be assigned before being used. Therefore, although you can declare the unmelted variables, it is not possible to pass it before it has values.
This will lead to a problem - if you just want to pass the variables to the method according to the reference, it is like a "out" parameter. For example, assume that you have a method, return the current hours, minutes, and seconds. If you write this:
Int thehour;
Int theminute;
Int thiscond;
TimeObject.gettime (ref thehour, ref theinute, ref thesecond)
Will get compilation errors because they are not initialized before using the Hour, THEMINUTE and THESECOND:
Use of unassigned local variable 'thehour
Use of unassigned local variable 'theminute'
Use of unassigned local variable 'twesecond'
You can initialize them to 0 or other no-harmless values to make the annoying compiler quietly:
INT theHOUR = 0;
INT theminute = 0;
Int thiscond = 0;
TimeObject.gettime (ref thehour, ref theinute, ref thesecond)
But this kind of writing is too stupid! Our intention is just to pass these variables to getTime as a reference, in which they are changed. In order to solve this problem, C # provides an OUT parameter modifier. OUT modifiers avoid demand for initialization of reference parameters. For example, the parameters provided for GetTime are not provided to the method any information, which is only the mechanism to obtain information from the method. Therefore, these three are marked as OUT parameters, avoiding the needs of their initialization in the method. When returned from the incoming method, the OUT parameter must be assigned. Here is the changed GetTime parameter declaration:
Public Void GetTime (Out Int H, Out Int M, Out Int S)
{
H = HOUR;
m = minute;
s = second;
}
Here is a new call to the getTime method:
TimeObject.gettime (Out the Hour, Out theminute, out thiscond);
[Translation: Complete examples are as follows:
C #: [Example 1: Method parameters using REF modified]
Using system;
Class Ryreftest
{
Public lyreftest ()
{
THIS.INTFIELD = 1;
This.Strfield = "strfield";
}
Protected int intfield;
Protected string strong;
Public void getfields (Ref Int Aint, Ref String Astr)
{
AINT = this.intfield;
Astr = this.strfield;
}
}
Class RyreftestApp
{
Public static void main ()
{
Ryreftest rrt = new ryreftest ();
INT INTVAR = 0; // If it is int intvar; the compiler will report the use of unbeatable variable INTVAR
String strvar = "0"; // If it is string strvar; the compiler will report the use of unfielded variables Strvar
RRT.Getfields (Ref Intvar, Ref Strvar);
Console.writeline ("intvar = {0}, strvar = {1}", intvar, strvar;
}
C #: [Example 2: Method parameters using OUT]
Using system;
Class Ryreftest
{
Public lyreftest ()
{
THIS.INTFIELD = 1;
This.Strfield = "strfield";
}
Protected int intfield;
Protected string strong;
Public void getfields (Out Int Aint, Out String Astr)
{
AINT = this.intfield;
Astr = this.strfield;
}
}
Class RyreftestApp
{
Public static void main ()
{
Ryreftest rrt = new ryreftest ();
INT INTVAR; // This is ok, if you write into int INTVAR = 0; of course, no problem J
String strvar; // This is ok, if you write string strvar = "0"; of course, no problem J
RRT.Getfields (out intvar, out strvar);
Console.writeline ("intvar = {0}, strvar = {1}", intvar, strvar);
}
}
】
[Translation: For more, please refer to a Comparrative Overview of C # Chinese version (Part 1), a Comparrative Overview of C # Chinese version (Part 2), C # Chief Designer Anders Hejlsberg Interview. 】
- Full text -