C# Programming/Classes
Cover | Introduction | Basics | Classes | Advanced Topics | The .NET Framework | Index
As in other object-oriented programming languages, the functionality of a C# program is implemented in one or more classes. The methods and properties of a class contain the code that defines how the class behaves.
C# classes support information hiding by encapsulating functionality in properties and methods and by enabling several types of polymorphism, including subtyping polymorphism via inheritance and parametric polymorphism via generics.
Several types of C# classes can be defined, including instance classes (standard classes that can be instantiated), static classes, and structures.
Classes are defined using the keyword class
followed by an identifier to name the class. Instances of the class can then be created with the new
keyword followed by the name of the class.
The code below defines a class called Employee
with properties Name
and Age
and with empty methods GetPayCheck()
and Work()
. It also defines a Sample
class that instantiates and uses the Employee
class:
publicclassEmployee { privateint_Age; privatestring_Name; publicintAge { get{return_Age;} set{_Age=value;} } publicstringName { get{return_Name;} set{_Name=value;} } publicvoidGetPayCheck() { } publicvoidWork() { } } publicclassSample { publicstaticvoidMain() { Employeemarissa=newEmployee(); marissa.Work(); marissa.GetPayCheck(); } }
Methods
[edit | edit source ]C# methods are class members containing code. They may have a return value and a list of parameters, as well as a generic type declaration. Like fields, methods can be static (associated with and accessed through the class) or instance (associated with and accessed through an object instance of the class methods as well as a generic type declaration.
From C# 4.0 onwards, it is possible for a method to have optional parameters with default values, as users of C++ already know. For example, the method
voidIncrement(refintx,intdx=1)
can be called with one parameter only, as the second parameter, dx, is initialised to a default value.[1]
Constructors of classes
[edit | edit source ]A class's constructors control its initialization. A constructor's code executes to initialize an instance of the class when a program requests a new object of the class's type. Constructors often set properties of their classes, but they are not restricted to doing so.
Like other methods, a constructor can have parameters. To create an object using a constructor with parameters, the new
command accepts parameters. The code below defines and then instantiates multiple objects of the Employee
class, once using the constructor without parameters and once using the version with a parameter:
publicclassEmployee { publicEmployee() { System.Console.WriteLine("Constructed without parameters"); } publicEmployee(stringstrText) { System.Console.WriteLine(strText); } } publicclassSample { publicstaticvoidMain() { System.Console.WriteLine("Start"); EmployeeAlfred=newEmployee(); EmployeeBilly=newEmployee("Parameter for construction"); System.Console.WriteLine("End"); }
Output:
Start Constructed without parameters Parameter for construction End
Constructors can call each other:
publicclassEmployee { publicEmployee(stringstrText,intiNumber) { ... } publicEmployee(stringstrText) :this(strText,1234)// calls the above constructor with user-specified text and the default number {} publicEmployee() :this("default text")// calls the above constructor with the default text {} }
Finalizers (Destructors)
[edit | edit source ]The opposite of constructors, finalizers define the final behavior of an object and execute when the object is no longer in use. Although they are often used in C++ to free resources reserved by an object, they are less frequently used in C# due to the .NET Framework Garbage Collector. An object's finalizer, which takes no parameters, is called sometime after an object is no longer referenced, but the complexities of garbage collection make the specific timing of finalizers uncertain.
publicclassEmployee { publicEmployee(stringstrText) { System.Console.WriteLine(strText); } ~Employee() { System.Console.WriteLine("Finalized!"); } publicstaticvoidMain() { Employeemarissa=newEmployee("Constructed!"); marissa=null; } }
Output:
Constructed! Finalized!
Properties
[edit | edit source ]C# properties are class members that expose functionality of methods using the syntax of fields. They simplify the syntax of calling traditional get and set methods (a.k.a. accessor methods). Like methods, they can be static or instance.
Properties are defined in the following way:
publicclassMyClass { privateintm_iField=3;// Sets integerField with a default value of 3 publicintIntegerField { get { returnm_iField;// get returns the field you specify when this property is assigned } set { m_iField=value;// set assigns the value assigned to the property of the field you specify } } }
An even shorter way for getter/setter methods are accessors that do both in one line:
classCulture { publicintTalkedCountries{get;set;} publicstringLanguage{get;set;} } classInterculturalDialogue { Cultureculture; culture.Language="Italian";// ==> culture.SetLanguage("Italian"); stringstrThisLanguage=culture.Language;// ==> ... = culture.GetLanguage(); }
The code is equivalent to a GetLanguage and SetLanguage method definition, but without having to define these methods. The user can directly access the member, if it is not private, of course.
The C# keyword value contains the value assigned to the property. After a property is defined it can be used like a variable. If you were to write some additional code in the get and set portions of the property it would work like a method and allow you to manipulate the data before it is read or written to the variable.
publicclassMyProgram { MyClassmyClass=newMyClass; Console.WriteLine(myClass.IntegerField);// Writes 3 to the command line. myClass.IntegerField=7;// Indirectly assigns 7 to the field myClass.m_iField }
Using properties in this way provides a clean, easy to use mechanism for protecting data.
Indexers
[edit | edit source ]C# indexers are class members that define the behavior of the array access operation (e.g. list[0]
to access the first element of list
even when list
is not an array).
To create an indexer, use the this keyword as in the following example:
publicstringthis[stringstrKey] { get{returncoll[strKey];} set{coll[strKey]=value;} }
This code will create a string indexer that returns a string value. For example, if the class was EmployeeCollection
, you could write code similar to the following:
EmployeeCollectione=newEmployeeCollection(); . . . strings=e["Jones"]; e["Smith"]="xxx";
Events
[edit | edit source ]C# events are class members that expose notifications to clients of the class. Events are only fired and never assigned.
usingSystem; // Note: You need to know some about delegate, properties and methods to understand this sample namespaceEventSample { /// <summary> /// This delegate defines the signature of the appropriate method /// </summary> publicdelegatevoidContractHandler(Employeesender); /// <summary> /// Employee class /// </summary> publicclassEmployee { /// <summary> /// Field for the info whether or not the Employee is engaged /// </summary> privateboolbIsEngaged=false; /// <summary> /// Age of the employee /// </summary> privateintiAge=-1; /// <summary> /// Name of the employee /// </summary> privateStringstrName=null; /// <summary> /// *** The our event *** /// Is a collection of methods that will be called when it fires /// </summary> publiceventContractHandlerEngaged; /// <summary> /// Standard constructor /// </summary> publicEmployee() { // Here, we are adding a new method with appropriate signature (defined by delegate) // note: when an event has no method and it was fired, it causes an exception! // for all effects when programming with events, assign one private method to event // or simply do a verification before firing it! --> if (event != null) this.Engaged+=newContractHandler(this.OnEngaged); } /// <summary> /// Event handler for the "engaged" event /// </summary> /// <param name="sender"> /// Sender object /// </param> privatevoidOnEngaged(Employeesender) { Console.WriteLine("private void OnEngaged was called! this employee is engaged now!"); } /// <summary> /// Accessor for the employee name /// </summary> publicstringName { get { returnstrName; } set { strName=value; } } /// <summary> /// Accessor for the employee age /// </summary> publicintAge { get { returnm_iAge; } set { m_iAge=value; } } /// <summary> /// Accessor for the information about employee engagement /// </summary> publicboolIsEngaged { get { returnbIsEngaged; } set { if(bIsEngaged==false&&value==true) { // here we fires event (call all the methods that it have) // all times when IsEngaged is false and set to true; Engaged(this); } bIsEngaged=value; } } } /// <summary> /// Class for the entry point /// </summary> publicclassEntryPointClass { staticvoidMain(string[]a_strArgs) { EmployeesimpleEmployee=newEmployee(); simpleEmployee.Age=18; simpleEmployee.Name="Samanta Rock"; // Here... // This is saying when the event fires, the method added to event are called too. // note that we cannot use = // is only += to add methods to event or -= do retire an event simpleEmployee.Engaged+=newContractHandler(SimpleEmployee_Engaged); // make attention here... // when I assign true to this property, // the event Engaged will be called // when event is called, all method that it have, are called! simpleEmployee.IsEngaged=true; Console.ReadLine(); return; } /// <summary> /// Event handler for the registered "engaged" event /// </summary> /// <param name="sender"> /// Event sender /// </param> staticvoidSimpleEmployee_Engaged(Employeesender) { Console.WriteLine("The employee {0} is happy!",sender.Name); } } }
See also here for details.
Operator overloading
[edit | edit source ]C# operator
definitions are class members that define or redefine the behavior of basic C# operators (called implicitly or explicitly) on instances of the class:
publicclassComplex { privatedoublem_dReal,m_dImaginary; publicdoubleReal { get{returnm_dReal;} set{m_dReal=value;} } publicdoubleImaginary { get{returnm_dImaginary;} set{m_dImaginary=value;} } // binary operator overloading publicstaticComplexoperator+(Complexc1,Complexc2) { returnnewComplex(){Real=c1.Real+c2.Real,Imaginary=c1.Imaginary+c2.Imaginary}; } // unary operator overloading publicstaticComplexoperator-(Complexc) { returnnewComplex(){Real=-c.Real,Imaginary=-c.Imaginary}; } // cast operator overloading (both implicit and explicit) publicstaticimplicitoperatordouble(Complexc) { // return the modulus - sqrt(x^2 + y^2) returnMath.Sqrt(Math.Pow(c.Real,2)+Math.Pow(c.Imaginary,2)); } publicstaticexplicitoperatorstring(Complexc) { // we should be overloading the ToString() method, but this is just a demonstration returnc.Real.ToString()+" + "+c.Imaginary.ToString()+"i"; } } publicclassStaticDemo { publicstaticvoidMain() { Complexnumber1=newComplex(){Real=1,Imaginary=2}; Complexnumber2=newComplex(){Real=4,Imaginary=10}; Complexnumber3=number1+number2;// number3 now has Real = 5, Imaginary = 12 number3=-number3;// number3 now has Real = -5, Imaginary = -12 doubletestNumber=number3;// testNumber will be set to the absolute value of number3 Console.WriteLine((string)number3);// This will print "-5 + -12i". // The cast to string was needed because that was an explicit cast operator. } }
Structures
[edit | edit source ]Structures, or structs, are defined with the struct
keyword followed by an identifier to name the structure. They are similar to classes, but have subtle differences. Structs are used as lightweight versions of classes that can help reduce memory management efforts when working with small data structures. In most situations, however, using a standard class is a better choice.
The principal difference between structs and classes is that instances of structs are values whereas instances of classes are references. Thus when you pass a struct to a function by value you get a copy of the object so changes to it are not reflected in the original because there are now two distinct objects but if you pass an instance of a class by reference then there is only one instance.
The Employee
structure below declares a public
and a private
field. Access to the private
field is granted through the public
property Name
:
structEmployee { publicintm_iAge; privatestringm_strName; publicstringName { get{returnm_strName;} set{m_strName=value;} } }
Since C# 2.0, is possible to have arrays inside structures, but only in unsafe contexts:
structdata { intheader; fixedintvalues[10]; }
The array is accessed using pointer arithmetic. Values are treat arrayed values as if they were C-style arrays using indexing, etc.
Structure constructors
[edit | edit source ]Structures need constructors - or better to say initialisers, as they do not construct but just initialise the memory[2] - so that their contents are not left uninitialised. Therefore, constructors without parametres are not allowed.
Structure variables can be assigned one to another if and only if the structure variable on the right side of the assignment are all initialised.[3]
structTimestamp { privateushortm_usYear; privateushortm_usMonth; privateushortm_usDayOfMonth; privateushortm_usHour; privateushortm_usMinute; privateushortm_usSecond; publicTimestamp(ushortusYear, ushortusMonth, ushortusDay, ushortusHour, ushortusMinute, ushortusSecond) { m_usYear=usYear-1900; m_usMonth=usMonth; m_usDay=usDay; m_usHour=usHour; m_usMinute=usMinute; m_usSecond=usSecond; } }
Static classes
[edit | edit source ]Static classes are commonly used to implement a Singleton Pattern. All of the methods, properties, and fields of a static
class are also static
(like the WriteLine()
method of the System.Console
class) and can thus be used without instantiating the static
class:
publicstaticclassWriter { publicstaticvoidWrite() { System.Console.WriteLine("Text"); } } publicclassSample { publicstaticvoidMain() { Writer.Write(); } }
References
[edit | edit source ]- ↑ [[[w:C_Sharp_syntax#Optional_parameters|Optional parameters]] "Optional parameters"]. Retrieved 2018年02月01日.
{{cite web}}
: Check|url=
value (help) - ↑
Greg Beech (2008年06月16日). "Structure constructors". http://social.msdn.microsoft.com/: MSDN. Retrieved 2012年04月12日.
Because structures are simply an inline area of memory, they cannot be null, and so the CLR has to be able to ensure that the area of memory is totally initialized rather than being partly garbage. For this reason, you'll often hear the 'constructors' on structures called (arguably more correctly) 'initializers' because the don't construct an object they just initialize an area of memory.
{{cite web}}
: External link in
(help)|location=
- ↑
John Sharp. "Microsoft® Visual C#® 2005 Step by Step / Copying Structure Variables". http://books.google.at/: Google Books. Retrieved 2012年04月12日.
You're allowed to initialize or assign one struct variable to another struct variable, but only if the struct variable on the right side is completely initialized (that is, if all its fields are initialized).
{{cite web}}
: External link in
(help)|location=
Cover | Introduction | Basics | Classes | Advanced Topics | The .NET Framework | Index