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

{

// Skip if 2

if (number == 2) continue;

// Stop iteration if 5 if (number == 5)

break;

Console.Write(number + ", ");

}

// Prints: 1, 3, 4,

Live Demo on .NET Fiddle

Notice that the order of iteration is guaranteed only for certain collections such as arrays and List, but not guaranteed for many other collections.

While IEnumerable is typically used to indicate enumerable collections, foreach only requires that the collection expose publicly the object GetEnumerator() method, which should return an object that exposes the bool MoveNext() method and the object Current { get; } property.

Section 52.20: dynamic

The dynamic keyword is used with dynamically typed objects. Objects declared as dynamic forego compile-time static checks, and are instead evaluated at runtime.

using System;

using System.Dynamic;

dynamic info = new ExpandoObject(); info.Id = 123;

info.Another = 456;

Console.WriteLine(info.Another);

// 456

Console.WriteLine(info.DoesntExist);

// Throws RuntimeBinderException

The following example uses dynamic with Newtonsoft's library Json.NET, in order to easily read data from a deserialized JSON file.

try

{

string json = @"{ x : 10, y : ""ho""}";

dynamic deserializedJson = JsonConvert.DeserializeObject(json); int x = deserializedJson.x;

string y = deserializedJson.y;

// int z = deserializedJson.z; // throws RuntimeBinderException

}

catch (RuntimeBinderException e)

{

//This exception is thrown when a property

//that wasn't assigned to a dynamic variable is used

}

GoalKicker.com – C# Notes for Professionals

242

There are some limitations associated with the dynamic keyword. One of them is the use of extension methods. The following example adds an extension method for string: SayHello.

static class StringExtensions

{

public static string SayHello(this string s) => $"Hello {s}!";

}

The first approach will be to call it as usual (as for a string):

var person = "Person"; Console.WriteLine(person.SayHello());

dynamic manager = "Manager"; Console.WriteLine(manager.SayHello()); // RuntimeBinderException

No compilation error, but at runtime you get a RuntimeBinderException. The workaround for this will be to call the extension method via the static class:

var helloManager = StringExtensions.SayHello(manager); Console.WriteLine(helloManager);

Section 52.21: try, catch, finally, throw

try, catch, finally, and throw allow you to handle exceptions in your code.

var processor = new InputProcessor();

//The code within the try block will be executed. If an exception occurs during execution of

//this code, execution will pass to the catch block corresponding to the exception type. try

{

processor.Process(input);

}

//If a FormatException is thrown during the try block, then this catch block

//will be executed.

catch (FormatException ex)

{

//Throw is a keyword that will manually throw an exception, triggering any catch block that is

//waiting for that exception type.

throw new InvalidOperationException("Invalid input", ex);

}

//catch can be used to catch all or any specific exceptions. This catch block,

//with no type specified, catches any exception that hasn't already been caught

//in a prior catch block.

catch

{

LogUnexpectedException();

throw; // Re-throws the original exception.

}

//The finally block is executed after all try-catch blocks have been; either after the try has

//succeeded in running all commands or after all exceptions have been caught.

finally

{

processor.Dispose();

}

Note: The return keyword can be used in try block, and the finally block will still be executed (just before

GoalKicker.com – C# Notes for Professionals

243

returning). For example:

try

{

connection.Open();

return connection.Get(query);

}

finally

{

connection.Close();

}

The statement connection.Close() will execute before the result of connection.Get(query) is returned.

Section 52.22: void

The reserved word "void" is an alias of System.Void type, and has two uses:

1. Declare a method that doesn't have a return value:

public void DoSomething()

{

// Do some work, don't return any value to the caller.

}

A method with a return type of void can still have the return keyword in its body. This is useful when you want to exit the method's execution and return the flow to the caller:

public void DoSomething()

{

// Do some work...

if (condition) return;

// Do some more work if the condition evaluated to false.

}

2. Declare a pointer to an unknown type in an unsafe context.

In an unsafe context, a type may be a pointer type, a value type, or a reference type. A pointer type declaration is usually type* identifier, where the type is a known type - i.e int* myInt, but can also be void* identifier, where the type is unknown.

Note that declaring a void pointer type is discouraged by Microsoft.

Section 52.23: namespace

The namespace keyword is an organization construct that helps us understand how a codebase is arranged. Namespaces in C# are virtual spaces rather than being in a physical folder.

namespace StackOverflow

{

namespace Documentation

{

namespace CSharp.Keywords

{

GoalKicker.com – C# Notes for Professionals

244

public class Program

{

public static void Main()

{

Console.WriteLine(typeof(Program).Namespace);

//StackOverflow.Documentation.CSharp.Keywords

}

}

}

}

}

Namespaces in C# can also be written in chained syntax. The following is equivalent to above:

namespace StackOverflow.Documentation.CSharp.Keywords

{

public class Program

{

public static void Main()

{

Console.WriteLine(typeof(Program).Namespace);

//StackOverflow.Documentation.CSharp.Keywords

}

}

}

Section 52.24: ref, out

The ref and out keywords cause an argument to be passed by reference, not by value. For value types, this means that the value of the variable can be changed by the callee.

int x = 5; ChangeX(ref x);

// The value of x could be different now

For reference types, the instance in the variable can not only be modified (as is the case without ref), but it can also be replaced altogether:

Address a = new Address();

ChangeFieldInAddress(a);

//a will be the same instance as before, even if it is modified

CreateANewInstance(ref a);

//a could be an entirely new instance now

The main di erence between the out and ref keyword is that ref requires the variable to be initialized by the caller, while out passes that responsibility to the callee.

To use an out parameter, both the method definition and the calling method must explicitly use the out keyword.

int number = 1;

Console.WriteLine("Before AddByRef: " + number); // number = 1 AddOneByRef(ref number);

Console.WriteLine("After AddByRef: " + number); // number = 2 SetByOut(out number);

Console.WriteLine("After SetByOut: " + number); // number = 34

void AddOneByRef(ref int value)

{

GoalKicker.com – C# Notes for Professionals

245