Skip to main content

Classes and objects (C# Specification Part 6)

Classes are the most fundamental of C#’s types. A class is a data structure that combines state (fields) and actions (methods and other function members) in a single unit. A class provides a definition for dynamically created instances of the class, also known as objects. Classes support inheritance and polymorphism, mechanisms whereby derived classes can extend and specialize base classes.

New classes are created using class declarations. A class declaration starts with a header that specifies the attributes and modifiers of the class, the name of the class, the base class (if given), and the interfaces implemented by the class. The header is followed by the class body, which consists of a list of member declarations written between the delimiters { and }.

The following is a declaration of a simple class named Point:
public class Point
{
      public int x, y;
      public Point(int x, int y) {
            this.x = x;
            this.y = y;
      }
}

Instances of classes are created using the new operator, which allocates memory for a new instance, invokes a constructor to initialize the instance, and returns a reference to the instance. The following statements create two Point objects and store references to those objects in two variables:

Point p1 = new Point(0, 0);
Point p2 = new Point(10, 20);


The memory occupied by an object is automatically reclaimed when the object is no longer in use. It is neither necessary nor possible to explicitly deallocate objects in C#.

Members 

The members of a class are either static members or instance members. Static members belong to classes, and instance members belong to objects (instances of classes).
The following table provides an overview of the kinds of members a class can contain.

Member
Description
Constants
Constant values associated with the class
Fields
Variables of the class
Methods
Computations and actions that can be performed by the class
Properties
Actions associated with reading and writing named properties of the class
Indexers
Actions associated with indexing instances of the class like an array
Events
Notifications that can be generated by the class
Operators
Conversions and expression operators supported by the class
Constructors
Actions required to initialize instances of the class or the class itself
Destructors
Actions to perform before instances of the class are permanently discarded
Types
Nested types declared by the class

Accessibility

Each member of a class has an associated accessibility, which controls the regions of program text that are able to access the member. There are five possible forms of accessibility. These are summarized in the following table.

Accessibility
Meaning
public
Access not limited
protected
Access limited to this class or classes derived from this class
internal
Access limited to this assembly
protected internal
Access limited to this assembly or classes derived from this class
private
Access limited to this class

Type parameters

A class definition may specify a set of type parameters by following the class name with angle brackets enclosing a list of type parameter names. The type parameters can the be used in the body of the class declarations to define the members of the class. In the following example, the type parameters of Pair are TFirst and TSecond:
public class Pair<TFirst,TSecond>
{
      public TFirst First;
      public TSecond Second;
}
A class type that is declared to take type parameters is called a generic class type. Struct, interface and delegate types can also be generic.
When the generic class is used, type arguments must be provided for each of the type parameters:
Pair<int,string> pair = new Pair<int,string> { First = 1, Second = “two” };
int i = pair.First;     // TFirst is int
string s = pair.Second; // TSecond is string

Base classes

A class declaration may specify a base class by following the class name and type parameters with a colon and the name of the base class. Omitting a base class specification is the same as deriving from type object. In the following example, the base class of Point3D is Point, and the base class of Point is object:

public class Point
{
      public int x, y;
      public Point(int x, int y) {
            this.x = x;
            this.y = y;
      }
}
public class Point3D: Point
{
      public int z;
      public Point3D(int x, int y, int z): base(x, y) {
            this.z = z;
      }
}

A class inherits the members of its base class. Inheritance means that a class implicitly contains all members of its base class, except for the instance and static constructors, and the destructors of the base class. A derived class can add new members to those it inherits, but it cannot remove the definition of an inherited member. In the previous example, Point3D inherits the x and y fields from Point, and every Point3D instance contains three fields, x, y, and z.

An implicit conversion exists from a class type to any of its base class types. Therefore, a variable of a class type can reference an instance of that class or an instance of any derived class. For example, given the previous class declarations, a variable of type Point can reference either a Point or a Point3D:
Point a = new Point(10, 20);
Point b = new Point3D(10, 20, 30);

Fields

A field is a variable that is associated with a class or with an instance of a class.
A field declared with the static modifier defines a static field. A static field identifies exactly one storage location. No matter how many instances of a class are created, there is only ever one copy of a static field.

A field declared without the static modifier defines an instance field. Every instance of a class contains a separate copy of all the instance fields of that class.

In the following example, each instance of the Color class has a separate copy of the r, g, and b instance fields, but there is only one copy of the Black, White, Red, Green, and Blue static fields:

public class Color
{
      public static readonly Color Black = new Color(0, 0, 0);
      public static readonly Color White = new Color(255, 255, 255);
      public static readonly Color Red = new Color(255, 0, 0);
      public static readonly Color Green = new Color(0, 255, 0);
      public static readonly Color Blue = new Color(0, 0, 255);
      private byte r, g, b;
      public Color(byte r, byte g, byte b) {
            this.r = r;
            this.g = g;
            this.b = b;
      }
}
As shown in the previous example, read-only fields may be declared with a readonly modifier. Assignment to a readonly field can only occur as part of the field’s declaration or in a constructor in the same class.

Methods

A method is a member that implements a computation or action that can be performed by an object or class. Static methods are accessed through the class. Instance methods are accessed through instances of the class.

Methods have a (possibly empty) list of parameters, which represent values or variable references passed to the method, and a return type, which specifies the type of the value computed and returned by the method. A method’s return type is void if it does not return a value.

The signature of a method must be unique in the class in which the method is declared. The signature of a method consists of the name of the method, the number of type parameters and the number, modifiers, and types of its parameters. The signature of a method does not include the return type.

Parameters

Parameters are used to pass values or variable references to methods. The parameters of a method get their actual values from the arguments that are specified when the method is invoked. There are four kinds of parameters: value parameters, reference parameters, output parameters, and parameter arrays.
A value parameter is used for input parameter passing. A value parameter corresponds to a local variable that gets its initial value from the argument that was passed for the parameter. Modifications to a value parameter do not affect the argument that was passed for the parameter.
Value parameters can be optional, by specifying a default value so that corresponding arguments can be omitted.
A reference parameter is used for both input and output parameter passing. The argument passed for a reference parameter must be a variable, and during execution of the method, the reference parameter represents the same storage location as the argument variable. A reference parameter is declared with the ref modifier. The following example shows the use of ref parameters.
using System;
class Test
{
      static void Swap(ref int x, ref int y) {
            int temp = x;
            x = y;
            y = temp;
      }
      static void Main() {
            int i = 1, j = 2;
            Swap(ref i, ref j);
            Console.WriteLine("{0} {1}", i, j);             // Outputs "2 1"
      }
}

An output parameter is used for output parameter passing. An output parameter is similar to a reference parameter except that the initial value of the caller-provided argument is unimportant and you must assign a value to the output parameter in method body . An output parameter is declared with the out modifier. The following example shows the use of out parameters.

using System;
class Test
{
      static void Divide(int x, int y, out int result, out int remainder) {
            result = x / y;
            remainder = x % y;
      }
      static void Main() {
            int res, rem;
            Divide(10, 3, out res, out rem);
            Console.WriteLine("{0} {1}", res, rem);   // Outputs "3 1"
      }
}

A parameter array permits a variable number of arguments to be passed to a method. A parameter array is declared with the params modifier. Only the last parameter of a method can be a parameter array, and the type of a parameter array must be a single-dimensional array type. The Write and WriteLine methods of the System.Console class are good examples of parameter array usage. They are declared as follows.
public class Console
{
      public static void Write(string fmt, params object[] args) {...}
      public static void WriteLine(string fmt, params object[] args) {...}
      ...
}

Within a method that uses a parameter array, the parameter array behaves exactly like a regular parameter of an array type. However, in an invocation of a method with a parameter array, it is possible to pass either a single argument of the parameter array type or any number of arguments of the element type of the parameter array. In the latter case, an array instance is automatically created and initialized with the given arguments. 

This example

Console.WriteLine("x={0} y={1} z={2}", x, y, z);
is equivalent to writing the following.
string s = "x={0} y={1} z={2}";
object[] args = new object[3];
args[0] = x;
args[1] = y;
args[2] = z;
Console.WriteLine(s, args);

Comments

Popular posts from this blog

gcAllowVeryLargeObjects Element

There are numerous new features coming with .NET 4.5 and here, on this blog, you can find several posts about it. But the feature we are goint to talk about today is very exciting, because we were waiting for it more than 10 years. Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio 2012, and create C# Console Application, like picture below. First lets create simple struct with two double members like example below: 1 2 3 4 5 6 7 8 9 10 11 12 public struct ComplexNumber {      public double Re;      public double Im;      public ComplexNumber( double re, double im)      {          Re=re;          Im=im;      } } As we know this structure consumes about 16

Support for debugging lambda expressions with Visual Studio 2015

Anyone who uses LINQ (or lambdas in general) and the debugger will quickly discover the dreaded message “Expression cannot contain lambda expressions”. Lack of lambda support has been a limitation of the Visual Studio Debugger ever since Lambdas were added to C# and Visual Basic.  With visual studio 2015 Microsoft has added support for debugging lambda expressions. Let’s first look at an example, and then I’ll walk you through current limitations. Example To try this yourself, create a new C# Console app with this code: using System.Diagnostics; using System.Linq; class Program { static void Main() { float[] values = Enumerable.Range(0, 100).Select(i => (float)i / 10).ToArray(); Debugger.Break(); } } Then compile, start debugging, and add “values.Where(v => (int)v == 3).ToArray()” in the Watch window. You’ll be happy to see the same as what the screenshot above shows you. I am using Visual Studio 2015 Preview and it has some limitations.

How to allow a very large object in .net application?

Since .NET 1.0 the memory limit of .NET object is 2GB. This means you cannot for example create array which contains elements with more than 2GB in total. If try to create such array, you will get the OutOfMemoryException. Let’s see an example how to produce OutOfMemoryException. Before that Open Visual Studio, and create C# Console Application. Lets create simple struct with two double members like example below: public struct ComplexNumber { public double Re; public double Im; public ComplexNumber(double re, double im) { Re = re; Im = im; } } As we know this structure consumes about 16 bytes of memory. So if we want to create array of this type which consume more than 2GB we need to create array at least with 134217728 instances. So this sample program below creates 130000000 (about 1,97 GB) of array. int maxCount = 130000000; ComplexNumber[] arr = null; try { arr = new ComplexNumber[maxCount]; } catch (Exception ex) { Console.WriteLine(ex.Message); } So if we run t