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

ptr[2] = 232;

...

Used in an unsafe context.

As with all pointers in C# there is no bounds checking on reads and assignments. Reading beyond the bounds of the allocated memory will have unpredictable results - it may access some arbitrary location within memory or it may cause an access violation exception.

//Allocate 1 byte

byte* ptr = stackalloc byte[1];

//Unpredictable results...

ptr[10] = 1; ptr[-1] = 2;

Stack allocated memory is automatically removed when the scope it was created in is exited. This means that you should never return the memory created with stackalloc or store it beyond the lifetime of the scope.

unsafe IntPtr Leak() {

//Allocate some memory on the stack var ptr = stackalloc byte[1024];

//Return a pointer to that memory (this exits the scope of "Leak") return new IntPtr(ptr);

}

unsafe void Bad() {

//ptr is now an invalid pointer, using it in any way will have //unpredictable results. This is exactly the same as accessing beyond //the bounds of the pointer.

var ptr = Leak();

}

stackalloc can only be used when declaring and initialising variables. The following is not valid:

byte* ptr;

...

ptr = stackalloc byte[1024];

Remarks:

stackalloc should only be used for performance optimizations (either for computation or interop). This is due to the fact that:

The garbage collector is not required as the memory is allocated on the stack rather than the heap - the memory is released as soon as the variable goes out of scope

It is faster to allocate memory on the stack rather than the heap Increase the chance of cache hits on the CPU due to the locality of data

Section 52.7: break

In a loop (for, foreach, do, while) the break statement aborts the execution of the innermost loop and returns to the code after it. Also it can be used with yield in which it specifies that an iterator has come to an end.

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

{

GoalKicker.com – C# Notes for Professionals

230

if (i == 5)

{

break;

}

Console.WriteLine("This will appear only 5 times, as the break will stop the loop.");

}

Live Demo on .NET Fiddle

foreach (var stuff in stuffCollection)

{

if (stuff.SomeStringProp == null) break;

// If stuff.SomeStringProp for any "stuff" is null, the loop is aborted.

Console.WriteLine(stuff.SomeStringProp);

}

The break-statement is also used in switch-case constructs to break out of a case or default segment.

switch(a)

{

case 5:

Console.WriteLine("a was 5!"); break;

default:

Console.WriteLine("a was something else!"); break;

}

In switch statements, the 'break' keyword is required at the end of each case statement. This is contrary to some languages that allow for 'falling through' to the next case statement in the series. Workarounds for this would include 'goto' statements or stacking the 'case' statements sequentially.

Following code will give numbers 0, 1, 2, ..., 9 and the last line will not be executed. yield break signifies the end of the function (not just a loop).

public static IEnumerable<int> GetNumbers()

{

int i = 0; while (true) {

if (i < 10) {

yield return i++; } else {

yield break;

}

}

Console.WriteLine("This line will not be executed");

}

Live Demo on .NET Fiddle

Note that unlike some other languages, there is no way to label a particular break in C#. This means that in the case of nested loops, only the innermost loop will be stopped:

foreach (var outerItem in outerList)

{

foreach (var innerItem in innerList)

GoalKicker.com – C# Notes for Professionals

231

{

if (innerItem.ShoudBreakForWhateverReason)

// This will only break out of the inner loop, the outer will continue: break;

}

}

If you want to break out of the outer loop here, you can use one of several di erent strategies, such as:

A goto statement to jump out of the whole looping structure.

A specific flag variable (shouldBreak in the following example) that can be checked at the end of each iteration of the outer loop.

Refactoring the code to use a return statement in the innermost loop body, or avoid the whole nested loop structure altogether.

bool shouldBreak = false; while(comeCondition)

{

while(otherCondition)

{

if (conditionToBreak)

{

//Either tranfer control flow to the label below...

goto endAllLooping;

//OR use a flag, which can be checked in the outer loop: shouldBreak = true;

}

}

if(shouldBreakNow)

{

break; // Break out of outer loop if flag was set to true

}

}

endAllLooping: // label from where control flow will continue

Section 52.8: const

const is used to represent values that will never change throughout the lifetime of the program. Its value is constant from compile-time, as opposed to the readonly keyword, whose value is constant from run-time.

For example, since the speed of light will never change, we can store it in a constant.

const double c = 299792458; // Speed of light

double CalculateEnergy(double mass)

{

return mass * c * c;

}

This is essentially the same as having return mass * 299792458 * 299792458, as the compiler will directly substitute c with its constant value.

As a result, c cannot be changed once declared. The following will produce a compile-time error:

const double c = 299792458; // Speed of light

GoalKicker.com – C# Notes for Professionals

232

c = 500; //compile-time error

A constant can be prefixed with the same access modifiers as methods:

private const double c = 299792458; public const double c = 299792458; internal const double c = 299792458;

const members are static by nature. However using static explicitly is not permitted.

You can also define method-local constants:

double CalculateEnergy(double mass)

{

const c = 299792458; return mass * c * c;

}

These can not be prefixed with a private or public keyword, since they are implicitly local to the method they are defined in.

Not all types can be used in a const declaration. The value types that are allowed, are the pre-defined types sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, and all enum types. Trying to declare const members with other value types (such as TimeSpan or Guid) will fail at compile-time.

For the special pre-defined reference type string, constants can be declared with any value. For all other reference types, constants can be declared but must always have the value null.

Because const values are known at compile-time, they are allowed as case labels in a switch statement, as standard arguments for optional parameters, as arguments to attribute specifications, and so on.

If const values are used across di erent assemblies, care must be taken with versioning. For example, if assembly A defines a public const int MaxRetries = 3;, and assembly B uses that constant, then if the value of MaxRetries is later changed to 5 in assembly A (which is then re-compiled), that change will not be e ective in assembly B unless assembly B is also re-compiled (with a reference to the new version of A).

For that reason, if a value might change in future revisions of the program, and if the value needs to be publicly visible, do not declare that value const unless you know that all dependent assemblies will be re-compiled whenever something is changed. The alternative is using static readonly instead of const, which is resolved at runtime.

Section 52.9: async, await

The await keyword was added as part of C# 5.0 release which is supported from Visual Studio 2012 onwards. It leverages Task Parallel Library (TPL) which made the multi-threading relatively easier. The async and await keywords are used in pair in the same function as shown below. The await keyword is used to pause the current asynchronous method's execution until the awaited asynchronous task is completed and/or its results returned. In order to use the await keyword, the method that uses it must be marked with the async keyword.

Using async with void is strongly discouraged. For more info you can look here.

Example:

public async Task DoSomethingAsync()

{

GoalKicker.com – C# Notes for Professionals

233