Here we will see the data types available in C#. Before examining the data types in C#, first we will try to understand the C# have two categories of data types.
- Value types
- Reference types
Value type data type is that which stores the value directly in the memory. Its just like int, float and double. But reference types variables only store the reference of the memory where the actual value is.
Value types are stored in memory in a stack where as the reference types are stored in managed heap.
Here is the list of predefined data types in C# which is also similar to data types in C. The category column will show whether its a value type or reference type.
Category | Type | Description | Example |
---|---|---|---|
Reference | object | The ultimate base type of all other types | object o = new Stack(); |
Reference | string | String type; a string is a sequence of Unicode characters | string s = “Hello”; |
value – int | sbtype | 8-bit signed integral type | sbyte val = 12; |
value – int | short | 16-bit signed integral type | sgort val = 12; |
value – int | int | 32-bit signed integral type | int val = 12; |
value – int | long | 64-bit signed integral type | long val1 = 12; long val2 = 34L; |
value – int | byte | 8-bit unsigned integral type | byte val1 = 12; byte val2 = 34U; |
value – int | ushort | 16-bit unsigned integral type | ushort val1 = 12; ushort val2 = 34U; |
value – int | uint | 32-bit unsigned integral type | uint val1 = 12; uint val2 = 34U; |
value – int | ulong | 64-bit unsigned integral type | ulong val1 = 12; ulong val2 = 34U; ulong val3 = 56L; ulong val4 = 78UL; |
value – float | float | Single-precision floating point type | float value = 1.23F; |
value – float | double | Double-precision floating point type | double val1 = 1.23 double val2 = 4.56D; |
value – bool | bool | Boolean type; a bool value is either true or false | bool value = true; |
value – chat | char | Character type; a char value is a Unicode character | char value = ‘h’; |
value – decimal | decimal | Precise decimal type with 28 significant digits | decimal value = 1.23M; |
Each of the predefined types is shorthand for a system-provided type. For example, the keyword int is shorthand for a struct named System.Int32. The two names can be used interchangeably, though it is considered good style to use the keyword rather than the complete system type name.
Arrays Data types
Arrays in C# may be single-dimensional or multi-dimensional which is similar to Arrays in C. Both rectangular and jagged arrays are supported. Single-dimensional arrays are the most common type, so this is a good starting point.
The example
1 2 3 4 5 6 7 8 9 10 11 | using System; class Test { static void Main() { int[] arr = new int[5]; for (int i = 0; i < arr.Length; i++) arr[i] = i * i; for (int i = 0; i < arr.Length; i++) Console.WriteLine("arr[{0}] = {1}", i, arr[i]); } } |
The type int[] used in the previous example is an array type. Array types are written using a non-array-type followed by one or more rank specifiers. The example
1 2 3 4 5 6 7 8 9 10 11 | class Test { static void Main() { int[] a1; // single-dimensional array of int int[,] a2; // 2-dimensional array of int int[,,] a3; // 3-dimensional array of int int[][] j2; // "jagged" array: array of (array of int) int[][][] j3; // array of (array of (array of int)) } } |
Arrays are reference types, and so the declaration of an array variable merely sets aside space for the reference to the array. Array instances are actually created via array initializers and array creation expressions. The example
1 2 3 4 5 6 7 8 9 10 11 12 | class Test { static void Main() { int[] a1 = new int[] {1, 2, 3}; int[,] a2 = new int[,] {{1, 2, 3}, {4, 5, 6}}; int[,,] a3 = new int[10, 20, 30]; int[][] j2 = new int[3][]; j2[0] = new int[] {1, 2, 3}; j2[1] = new int[] {1, 2, 3, 4, 5, 6}; j2[2] = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9}; } } |
Types ref & out
C# supports two major kinds of types: value types and reference types. Value types include simple types (e.g., char, int, and float), enum types, and struct types. Reference types include class types, interface types, delegate types, and array types.
Value types differ from reference types in that variables of the value types directly contain their data, whereas variables of the reference types store references to objects. With reference types, it is possible for two variables to reference the same object, and thus possible for operations on one variable to affect the object referenced by the other variable. With value types, the variables each have their own copy of the data, and it is not possible for operations on one to affect the other.
Using Keyword: ref
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | private void DoReference(int Value1, ref int Value2) { // Increment the two values. Value1++; Value2++; } private void btnRefTest_Click(object sender, System.EventArgs e) { // Create two variables and assign them values. int Value1 = 1; int Value2 = 1; // Call a function using a reference for one and standard // calling technique for the other. DoReference(Value1, ref Value2); // Display the results. MessageBox.Show("Value1 Results: " + Value1.ToString() + "rnValue2 Results: " + Value2.ToString(), "Output of Reference Test", MessageBoxButtons.OK, MessageBoxIcon.Information); } |
The Out keyword serves a different purpose from the Ref keyword. In this case, it enables you to pass an uninitialized value to a method and receive it back initialized to some value. You gain three benefits when using this technique.
- Slight performance gain by passing the value once
- Less code
- Slightly lower memory cost
Using Keyword: out
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private void DoOut(out int Value1) { // Initialize the value. Value1 = 3; } private void btnOutTest_Click(object sender, System.EventArgs e) { // Create a variable, but don't initialize it. int Value1; // Call a function using the Out keyword. DoOut(out Value1); // Display the result. MessageBox.Show("Value1 Results: " + Value1.ToString(), "Output of Out Test", MessageBoxButtons.OK, MessageBoxIcon.Information); } |
Interfaces
An interface is a contract between the client and server that determines how the two will interact. The interface specifies the methods, properties, and events used for communication, without actually providing an implementation of any of these elements. In short, you should look at an interface as a blueprint for communication. In some respects, an interface is similar to an abstract class. The difference is that an abstract class is used as a base class to create other classes, while an interface is mixed in an inheritance tree that determines the behavior of a new class.
Creating interfaces is important when a developer wants to provide more than one implementation but ensure the contract between client and server always remains the same. The best example of interface use is in components and controls. Both rely on the use of interfaces to define their behavior. In fact, the interface is essential in determining how the client will react to the component or control. While the implementation of the interface varies by component or control, the usage of the interface remains the same, which allows client and server to interact using a standardized method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | namespace Sample { // Create a simple interface. public interface ISimple { // Methods only need to show an argument list. void MyMethod(int Variable); // Add properties without implementation, // but always include get and/or set. int MyProperty { get; set; } } } |
Delegates
Delegates enable scenarios that C++ and some other languages have addressed with function pointers. Unlike function pointers, delegates are object-oriented, type-safe, and secure.
Delegates are reference types that derive from a common base class: System.Delegate. A delegate instance encapsulates a method a callable entity. For instance methods, a callable entity consists of an instance and a method on the instance. If you have a delegate instance and an appropriate set of arguments, you can invoke the delegate with the arguments. Similarly, for static methods, a callable entity consists of a class and a static method on the class.
An interesting and useful property of a delegate is that it does not know or care about the class of the object that it references. Any object will do; all that matters is that the method’s signature matches the delegate’s. This makes delegates perfectly suited for “anonymous” invocation. This is a powerful capability. There are three steps in defining and using delegates: declaration, instantiation, and nvocation. Delegates are declared using delegate declaration syntax. A delegate that takes no arguments and returns void can be declared with
1 | delegate void SimpleDelegate(); |
A delegate instance can be instantiated using the new keyword, and referencing either an instance or class method that conforms to the signature specified by the delegate. Once a delegate has been instantiated, it can be called using method call syntax. In the example
1 2 3 4 5 6 7 8 9 10 | class Test { static void F() { System.Console.WriteLine("Test.F"); } static void Main() { SimpleDelegate d = new SimpleDelegate(F); d(); } } |