Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

}

Section 52.32: continue

Immediately pass control to the next iteration of the enclosing loop construct (for, foreach, do, while):

for (var i = 0; i < 10; i++)

{

if (i < 5)

{

continue;

}

Console.WriteLine(i);

}

Output:

5

6

7

8

9

Live Demo on .NET Fiddle

var stuff = new [] {"a", "b", null, "c", "d"};

foreach (var s in stuff)

{

if (s == null)

{

continue;

}

Console.WriteLine(s);

}

Output:

a b c d

Live Demo on .NET Fiddle

Section 52.33: string

string is an alias to the .NET datatype System.String, which allows text (sequences of characters) to be stored.

Notation:

string a = "Hello"; var b = "world";

GoalKicker.com – C# Notes for Professionals

254

var f = new string(new []{ 'h', 'i', '!' }); // hi!

Each character in the string is encoded in UTF-16, which means that each character will require a minimum 2 bytes of storage space.

Section 52.34: return

MSDN: The return statement terminates execution of the method in which it appears and returns control to the calling method. It can also return an optional value. If the method is a void type, the return statement can be omitted.

public int Sum(int valueA, int valueB)

{

return valueA + valueB;

}

public void Terminate(bool terminateEarly)

{

if (terminateEarly) return; // method returns to caller if true was passed in else Console.WriteLine("Not early"); // prints only if terminateEarly was false

}

Section 52.35: unsafe

The unsafe keyword can be used in type or method declarations or to declare an inline block.

The purpose of this keyword is to enable the use of the unsafe subset of C# for the block in question. The unsafe subset includes features like pointers, stack allocation, C-like arrays, and so on.

Unsafe code is not verifiable and that's why its usage is discouraged. Compilation of unsafe code requires passing a switch to the C# compiler. Additionally, the CLR requires that the running assembly has full trust.

Despite these limitations, unsafe code has valid usages in making some operations more performant (e.g. array indexing) or easier (e.g. interop with some unmanaged libraries).

As a very simple example

// compile with /unsafe class UnsafeTest

{

unsafe static void SquarePtrParam(int* p)

{

*p *= *p; // the '*' dereferences the pointer.

//Since we passed in "the address of i", this becomes "i *= i"

}

unsafe static void Main()

{

int i = 5;

// Unsafe method: uses address-of operator (&):

SquarePtrParam(&i); // "&i" means "the address of i". The behavior is similar to "ref i"

Console.WriteLine(i); // Output: 25

}

}

GoalKicker.com – C# Notes for Professionals

255

While working with pointers, we can change the values of memory locations directly, rather than having to address them by name. Note that this often requires the use of the fixed keyword to prevent possible memory corruption as the garbage collector moves things around (otherwise, you may get error CS0212). Since a variable that has been "fixed" cannot be written to, we also often have to have a second pointer that starts out pointing to the same location as the first.

void Main()

{

int[] intArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

UnsafeSquareArray(intArray); foreach(int i in intArray)

Console.WriteLine(i);

}

unsafe static void UnsafeSquareArray(int[] pArr)

{

int len = pArr.Length;

//in C or C++, we could say

//int* a = &(pArr[0])

//however, C# requires you to "fix" the variable first fixed(int* fixedPointer = &(pArr[0]))

{

//Declare a new int pointer because "fixedPointer" cannot be written to.

//"p" points to the same address space, but we can modify it

int* p = fixedPointer;

for (int i = 0; i < len; i++)

{

*p *= *p; //square the value, just like we did in SquarePtrParam, above p++; //move the pointer to the next memory space.

//NOTE that the pointer will move 4 bytes since "p" is an

//int pointer and an int takes 4 bytes

//the above 2 lines could be written as one, like this: // "*p *= *p++;"

}

}

}

Output:

1

4

9

16

25

36

49

64

81

100

unsafe also allows the use of stackalloc which will allocate memory on the stack like _alloca in the C run-time library. We can modify the above example to use stackalloc as follows:

unsafe void Main()

{

GoalKicker.com – C# Notes for Professionals

256

const int len=10;

int* seedArray = stackalloc int[len];

//We can no longer use the initializer "{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}" as before.

//We have at least 2 options to populate the array. The end result of either

//option will be the same (doing both will also be the same here).

//FIRST OPTION:

int* p = seedArray; // we don't want to lose where the array starts, so we // create a shadow copy of the pointer

for(int i=1; i<=len; i++) *p++ = i;

//end of first option

//SECOND OPTION:

for(int i=0; i<len; i++) seedArray[i] = i+1;

//end of second option

UnsafeSquareArray(seedArray, len); for(int i=0; i< len; i++)

Console.WriteLine(seedArray[i]);

}

//Now that we are dealing directly in pointers, we don't need to mess around with // "fixed", which dramatically simplifies the code

unsafe static void UnsafeSquareArray(int* p, int len)

{

for (int i = 0; i < len; i++) *p *= *p++;

}

(Output is the same as above)

Section 52.36: switch

The switch statement is a control statement that selects a switch section to execute from a list of candidates. A switch statement includes one or more switch sections. Each switch section contains one or more case labels followed by one or more statements. If no case label contains a matching value, control is transferred to the default section, if there is one. Case fall-through is not supported in C#, strictly speaking. However, if 1 or more case labels are empty, execution will follow the code of the next case block which contains code. This allows grouping of multiple case labels with the same implementation. In the following example, if month equals 12, the code in case 2 will be executed since the case labels 12 1 and 2 are grouped. If a case block is not empty, a break must be present before the next case label, otherwise the compiler will flag an error.

int month = DateTime.Now.Month; // this is expected to be 1-12 for Jan-Dec

switch (month)

{

case 12: case 1: case 2:

Console.WriteLine("Winter"); break;

case 3: case 4: case 5:

Console.WriteLine("Spring"); break;

GoalKicker.com – C# Notes for Professionals

257