C# Specification Flashcards
Describe the type system
The type system in C# is a unified type system and has 2 types. Value types and references types. All types including user-defined references types and value types inherit from the same root type called “object”. The root type provides a common set of operations which allows all types to be stored, transported and operated upon in a consistent manner.
Program structure
C# programs consist of source files which contain type declarations and members organized in namespaces. When compiled, executable code in the form of Intermediate Language instructions and metadata are generated from the types and packaged into either application (.exe) or library (.dll) assemblies.
When executed, the IL code is converted into processor-specific code by the Just-In-Time (JIT) compiler from the .NET Common Language Runtime.
Describe value types
A value type variable directly contains the data and is stored on the stack. Value type variables have their own copy of the data and operations on variables do not affect one another. Therefore, when passing a value type to a method, the method receives a copy of the variable value by default. However, ref and out parameter variables can be used to share variables across different scopes.
Value types consist of
Simple types
Signed integral: sbyte, short, int, long
Unsigned integral: byte, ushort, uint, ulong
Unicode characters: char
IEEE floating point: float, double
High-precision decimal: decimal
Boolean: bool
Enum types
User-defined types of the form enum E {…}
Struct types
User-defined types of the form struct S {…}
Nullable types
Extensions of all other value types with a null value
Describe reference types
A reference type variable contains a reference to it’s data which is stored on the heap. Multiple reference type variables can reference the same object and therefore can have an affect on one another.
Reference types consist of
Class types Ultimate base class of all other types: object Unicode strings: string User-defined types of the form class C {...} Interface types User-defined types of the form interface I {...} Array types Single- and multi-dimensional, for example, int[] and int[,] Delegate types User-defined types of the form e.g. delegate int D(...)
Numeric types
Signed integral 8 sbyte -128...127 16 short -32,768...32,767 32 int -2,147,483,648...2,147,483,647 64 long -9,223,372,036,854,775,808...9,223,372,036,854,775,807
Unsigned integral 8 byte 0...255 16 ushort 0...65,535 32 uint 0...4,294,967,295 64 ulong 0...18,446,744,073,709,551,615
Floating point
32 float 1.5 × 10^−45 to 3.4 × 10^38, 7-digit precision
64 double 5.0 × 10^−324 to 1.7 × 10^308, 15-digit precision
Decimal
128 decimal 1.0 × 10^−28 to 7.9 × 10^28, 28-digit precision
Struct vs. Class
Structs are values types and classes are reference types. Structs and Classes both inherit from object and contain members (fields, methods, properties and constructors) but, structs do not support user-defined inheritance and polymorphism although they can implement interfaces. Structs can also be assigned a null value which allows for Nullables.
Describe Boxing and Unboxing
Since C# has a unified type system, every type including all values types inherit from object. This allows for values types to be converted into reference types and back to values types. Boxing is converting a value type to an object (a reference type) and Unboxing is converting a reference type to a value type. This conversion does have a performance impact in that the data is being copied from the stack to the heap or from the heap to the stack.
What is a Nullable value type?
Value types are made nullable by wrapping them in the Nullable struct such as Nullable. Nullable and int? are identical declarations. You can also make a struct Nullable the same way i.e. Nullable or MyStruct? The Nullable adds 2 properties HasValue and Value. HasValue is a flag that keeps tract of whether a value has been assigned or not. If HasValue is false then access the Value property will result in and exception. Even though Nullable is a struct and therefore a value type, the null value can be assigned with the help of special rules in the compiler.
Type Pattern matching with ‘is’:
What is the result of this expression?
int? a = 42; if (a is int valueOfA) { Console.WriteLine($"a is {valueOfA}"); } else { Console.WriteLine("a does not have a value"); }
a is 42
Type Pattern matching with ‘is’:
What is the result of this expression?
int? a = null; if (a is int valueOfA) { Console.WriteLine($"a is {valueOfA}"); } else { Console.WriteLine("a does not have a value"); }
a does not have a value
checked and unchecked
C# statements can execute in either checked or unchecked context. In a checked context, arithmetic overflow raises an exception. In an unchecked context, arithmetic overflow is ignored and the result is truncated by discarding any high-order bits that don’t fit in the destination type.
The following operations are affected by the overflow checking:
Expressions using the following predefined operators on integral types:
++, –, unary -, +, -, *, /
Explicit numeric conversions between integral types, or from float or double to an integral type.
If neither checked nor unchecked is specified, the default context for non-constant expressions (expressions that are evaluated at run time) is defined by the value of the -checked compiler option. By default the value of that option is unset and arithmetic operations are executed in an unchecked context.
For constant expressions (expressions that can be fully evaluated at compile time), the default context is always checked. Unless a constant expression is explicitly placed in an unchecked context, overflows that occur during the compile-time evaluation of the expression cause compile-time errors.
Describe class member Accessibility
All types and type members have an accessibility level. The accessibility level controls whether they can be used from other code in your assembly or other assemblies. Use the following access modifiers to specify the accessibility of a type or member when you declare it:
public - The type or member can be accessed by any other code in the same assembly or another assembly that references it.
private - The type or member can be accessed only by code in the same class or struct.
protected - The type or member can be accessed only by code in the same class, or in a class that is derived from that class.
internal - The type or member can be accessed by any code in the same assembly, but not from another assembly.
protected internal - The type or member can be accessed by any code in the assembly in which it’s declared, or from within a derived class in another assembly.
private protected - The type or member can be accessed only within its declaring assembly, by code in the same class or in a type that is derived from that class.
none - defaults to internal
ref vs. out
Ref and out keywords in C# are used to pass arguments within a method or function. Both indicate that an argument/parameter is passed by reference. By default parameters are passed to a method by value. By using these keywords (ref and out) we can pass a parameter by reference.
Ref:
- The parameter or argument must be initialized first before it is passed to ref.
- It is not required to assign or initialize the value of a parameter (which is passed by ref) before returning to the calling method.
- Passing a parameter value by Ref is useful when the called method is also needed to modify the pass parameter.
- It is not compulsory to initialize a parameter value before using it in a calling method.
- When we use REF, data can be passed bi-directionally.
Out:
- It is not compulsory to initialize a parameter or argument before it is passed to an out.
- A called method is required to assign or initialize a value of a parameter (which is passed to an out) before returning to the calling method.
- Declaring a parameter to an out method is useful when multiple values need to be returned from a function or method.
- A parameter value must be initialized within the calling method before its use.
- When we use OUT data is passed only in a unidirectional way (from the called method to the caller method).
- Both ref and out are treated differently at run time and they are treated the same at compile time.
- Properties are not variables, therefore it cannot be passed as an out or ref parameter.
Instance Constructor vs. Static Constructor
An instance constructor is a member that implements the actions required to initialize an instance of a class. A static constructor is a member that implements the actions required to initialize a class itself when it is first loaded.
Describe Indexers
An indexer is a member that enables objects to be indexed in the same way as an array. An indexer is declared like a property except that the name of the member is this followed by a parameter list written between the delimiters [ and ].
class SampleCollection { // Declare an array to store the data elements. private T[] arr = new T[100];
// Define the indexer to allow client code to use [] notation. public T this[int i] { get { return arr[i]; } set { arr[i] = value; } } }