C# Concepts: Asynchronous Programming with Async and Await, Casting, … and more

In this ongoing post, I will add more and more tips and useful links to better understand some topics related to C#

  • Value Types vs Reference Types
  • Casting: “as ClassName” vs (ClassName)
  • Enum
  • Asynchronous Programming with Async and Await
  • Navigation in an XML to get the attribute value of a node
  • Lambda expressions/statement
  • Visual Studio snippets
  • Size of both references and data types

 

===================================================

Value Types vs Reference Types

Both primitive types (such as int, float, bool and char) and Structs are value types, while classes are reference types.

When a value-type instance is created, a single space in memory is allocated to store the value. When the runtime deals with a value type, it’s dealing directly with its underlying data and this can be very efficient, particularly with primitive types.

With reference types, on the contrary, an object is created in memory, and then handled through a separate reference—rather like a pointer.

This is of particular interest when passing parameters to methods. In C#, parameters are (by default) passed by value, meaning that they are implicitly copied when passed to the method. For value-type parameters, this means physically copying the instance, while for reference-types it means copying a reference.

See this link for examples and more details.

 

===================================================

Casting: “as ClassName” vs (ClassName)

With the “classic” method, if the cast fails, an exception is thrown. With the as method, it results in null, which can be checked for, and avoid an exception being thrown.

Because the as method can only be used for types that can be assigned a null value, usually, you can only use “as” with reference types while, if you are typecasting to a value type, you must still use only the “classic” method, unless it is a nullable value type: infact when .NET 2.0 came out, it introduced the concept of a nullable value type and since these types can be assigned a null value, they are valid to use with the as operator.

SomeClass someObject = (ClassName) obj; //it throws a class cast exception if obj isn't that ClassName

one can use this syntax:

ClassName someObject = obj as ClassName; //it returns null if obj isn't that ClassName

 

===================================================

Enum

Enums are strongly typed constants. They are essentially unique types that allow you to assign symbolic names to integral values. In the C# tradition, they are strongly typed, meaning that an enum of one type may not be implicitly assigned to an enum of another type even though the underlying value of their members are the same. Along the same lines, integral types and enums are not implicitly interchangable. All assignments between different enum types and integral types require an explicit cast.

You can find a good tutorial here.

public enum TipoTimbratura {Uscita = 0, Entrata = 1}

//poi nella classe che la usa:
TipoTimbratura tipo = TipoTimbratura.Entrata;

String tipoString = tipo.ToString(); //assegna la stringa "Entrata"

if (tipo ==TipoTimbratura.Entrata){...}

//per creare l'enum a partire da una stringa che ne è il valore:
TipoTimbratura tipo = (TipoTimbratura)Enum.Parse(typeof(TipoTimbratura), Uscita");

//per creare l'enum a partire dall'int
TipoTimbratura tipo = (TipoTimbratura)tipoInt;

//per avere la stringa a partire da un enum:
Enum.GetName(typeof(TipoTimbratura), tipo);//restituisce la stringa "Uscita"

//se si vuole ciclare su tutti i valori numerici:
foreach (byte val in Enum.GetValues(typeof(TipoTimbratura))) {...}

//se si vuole ciclare su tutti i valori stringa:
foreach (string tipo in Enum.GetNames(typeof(TipoTimbratura))) {...}

//inoltre per prendere il valore numerico sapendo la stringa:
int value = (int)TipoTimbratura.Uscita; //restituisce l'intero 0
int tipoInt = Int32.Parse("Entrata"); //restituisce l'intero 1
enum Direction {
	North,
	East,
	South,
	West
}

foreach (string direction in Enum.GetNames(typeof(Direction))) {
	Console.WriteLine("Direction Member: {0}\n Value: {1}",
	direction, (int)Enum.Parse(typeof(Direction), direction));
}
value = Convert.ToInt64(WrState.Dispatched)

 

===================================================

Asynchronous Programming with Async and Await

One of the more powerful (and not so easy to be understood) approach for the async programming in C# (.NET Framework  and the Windows Runtime) is the use of the async and await keywords.

This article (C#) from the MSDN site can be very useful to a first understanding what happens in an async method.

async (C# Reference) / await (C# Reference)

Video:

Six Essential Tips For Async – Introduction

  1. Async void is for top-level event-handlers only, and event-like things. Don’t use it elsewhere in your code.
  2. It’s crucial to distinguish CPU-bound work (should be done on threadpool) from IO-bound work (which needn’t).
  3. Async library methods should have chunky async APIs not chatty. But if chatty is unavoidable, know about these micro-optimizations to reduce heap allocation overheads.
  4. Async library methods should consider task.ConfigureAwait(false) to reduce their impact on the UI message queue.

Tip 3: Wrap events up in Task-returning APIs and await them

Async Programming Improvements for C++ and UWP

===================================================

Example: resolve all GeoCoordinates that are missing in a list of objects that contains also the address of the location and return the list with all the GeoCoodinates possibly valorized

 private async Task SetExchangeStopGeoCoordinate() {
            int found = 0;
            try {
                ExchangeStopList exchangeStopList = ((MissionDataSource)DataContext).Mission.ExchangeStops;
                List<Task> tasks = new List<Task>();
                int i = 0;
                foreach(var exchangeStop in exchangeStopList) {
                    if(exchangeStop.GeoLocation.GeoCoordinate == null) {
                        //GeoCoordinates are not valorized so they should be deduced from the address field
                        try {
                            Task task = exchangeStop.GeoLocation.ResolveCoordinates(((MissionDataSource)DataContext).MyGeoCoordinate);
                            tasks.Add(task);
                        } catch(Exception ex) {
                            MessageBox.Show(LocalizedStrings.GetString(ex.Message), LocalizedStrings.GetString("ExceptionCaption"), MessageBoxButton.OK);
                        }
                    }
                    if(exchangeStop.Description == null) {
                        exchangeStop.Description = i++.ToString(CultureInfo.InvariantCulture);
                    }
                }
                if(tasks.Count > 0) {
                    App.RunProgressBar(this, true, String.Format(LocalizedStrings.GetString("ResolveCoordinates"), tasks.Count));
                    await Task.WhenAll(tasks);
                    foreach(var task in tasks) {
                        bool resultFound = await task;//exchangeStopList[i].GeoLocation.GeoCoordinate = await task;
                        if(resultFound) {
                            found++;
                        }
                    }
                }
                App.RunProgressBar(this, false); //coordinate risolte
            } catch(UnauthorizedAccessException) {
                MessageBox.Show(LocalizedStrings.GetString("LocationDisabled"));
            } catch(Exception ex) {
                // Something else happened while acquiring the location.
                MessageBox.Show(ex.Message);
            }
            return found;
        }
 public  async Task ResolveCoordinates(GeoCoordinate myGeoCoordinate ) {
            StringBuilder sbSearchTerm = new StringBuilder();
            sbSearchTerm.Append(((this.Street != null) ? (this.Street) : ""))
              .Append(((this.Number != null) ? (" " + this.Number) : ""))
              .Append(((this.City != null) ? ("," + this.City) : ""))
              .Append(((this.Zip != null) ? ("," + this.Zip) : ""))
              .Append(((this.Country != null) ? ("," + this.Country) : ""));
            string searchTerm = sbSearchTerm.ToString();
            var geocodeQuery = new GeocodeQuery {
                SearchTerm = searchTerm,//"Ferry Building, San-Francisco"//"46 Anglesea St, Auckland"
                GeoCoordinate = myGeoCoordinate == null ? new GeoCoordinate(0, 0) : myGeoCoordinate //GeoCoordinate = _myGeoCoordinate == null ? new GeoCoordinate(0, 0) : _myGeoCoordinate
            };
            int retry = 2;
            IList mapLocations = null;
            while(retry > 0 && (mapLocations == null || mapLocations.Count == 0)) {
                try {
                    mapLocations = await geocodeQuery.ExecuteAsync(); //var locations = await geocodeQuery.ExecuteAsync();
                } catch(Exception ex) {
                    MessageBox.Show("Exception: " + ex.Message);
                }
                retry--;
            }

            if(mapLocations != null && mapLocations.Count > 0) {
                if(mapLocations.Count == 1) {
                    this.GeoCoordinate = mapLocations.First().GeoCoordinate;
                    if(this.GeoCoordinate == null) {
                        //anche se è strato trovato, le GeoCoordinate non sono fornite
                        return false;
                    }
                    return true;
                } else {
                    //sono state trovate più corrispondenze: chiedere all'utente quale scegliere (per default la prima)

                    //http://stackoverflow.com/questions/12858501/is-it-possible-to-await-an-event-instead-of-another-async-method
                    TaskCompletionSource continueClicked = null;
                    DataTemplate dataTemplate = CreateDataTemplate();
                    List locationList = new List();
                    for(int i = 0; i  {
                        if(streetListPicker.ListPickerMode == ListPickerMode.Expanded) {
                            e1.Cancel = true;
                        } else if(streetListPicker.ListPickerMode == ListPickerMode.Full) {
                            e1.Cancel = true;
                            messageBox.Visibility = Visibility.Collapsed;
                            //????? TODO non funziona https://phone.codeplex.com/workitem/11357
                            streetListPicker.IsEnabled = true;
                            streetListPicker.Visibility = Visibility.Visible;
                            streetListPicker.Focus();
                            streetListPicker.UpdateLayout();
                        }
                    };
                    messageBox.Dismissed += (s2, e2) => {
                        switch(e2.Result) {
                            case CustomMessageBoxResult.LeftButton: {
                                    // save the choosen MapLocation
                                    int selectedIndex = streetListPicker.SelectedIndex;
                                    this.GeoCoordinate =
                                        mapLocations.ElementAt(selectedIndex).GeoCoordinate;
                                    if(this.GeoCoordinate == null) {
                                        //anche se è stato trovato, le GeoCOordinate non sono fornite
                                        if(continueClicked != null)
                                            continueClicked.TrySetResult(false);
                                    } else {
                                        if(continueClicked != null)
                                            continueClicked.TrySetResult(true);
                                    }

                                    break;
                                }
                            case CustomMessageBoxResult.RightButton:
                            case CustomMessageBoxResult.None: {
                                    // scelgo di default il primo (dovrebbe essere il più probabile, vicino alla mia posizione
                                this.GeoCoordinate = mapLocations.First().GeoCoordinate;
                                if(this.GeoCoordinate == null) {
                                        //anche se è strato trovato, le GeoCoordinate non sono fornite
                                        if(continueClicked != null) {
                                            continueClicked.TrySetResult(false);
                                        }
                                    }
                                    if(continueClicked != null) {
                                        continueClicked.TrySetResult(true);
                                    }
                                    break;
                                }
                            default:
                                break;
                        }
                    };
                    streetListPicker.SelectionChanged += (s3, e3) => {
                        if((streetListPicker.ListPickerMode == ListPickerMode.Full)) {
                            messageBox.Visibility = Visibility.Visible;
                        }
                    };
                    messageBox.Show();
                    continueClicked = new TaskCompletionSource();
                    bool b = await continueClicked.Task;
                    return b;
                }
            } else {
                return false;
            }
        }

 

===================================================

Navigation in an XML to get the attribute value of a node:

Solution 1: using XElement from System.Xml.Linq namespace

XElement sheet = XElement.Parse(MyXml);
var temp = sheet.Descendants(sheet.Name.Namespace + "<searched node>");
XElement x = temp.FirstOrDefault();

where x is a node element and then , through methods and properties, all the attributes can be accessed.

==================================

Solution 2: using XmlDocument

XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xmlString);
var nodo = xdoc.GetElementsByTagName("myNodeName");
for (int i = 0; i &lt; nodo.Count; i++) {
  var myChild= nodo.Item(i);
  for (int j = 0; j &lt; myChild.ChildNodes.Count; j++) {
    var attributo = myChild["myAttributeName"];
  }
}

 

===================================================

Lambda expressions: [see Lambda Expressions (C# Programming Guide)]

A lambda expression is an anonymous function and it is mostly used to create delegates in LINQ. Simply put, it’s a method without a declaration, i.e., access modifier, return value declaration, and name.

Lambda basic definition: Parameters (if any) => Executed code

E.g.

(x, y) => x == y

Sometimes it is difficult or impossible for the compiler to infer the input types. When this occurs, you can specify the types explicitly as shown in the following example:

(int x, string s) => s.Length > x

Specify zero input parameters with empty parentheses:

() => SomeMethod()

Advantages:

  1. Reduced typing. No need to specify the name of the function, its return type, and its access modifier.
  2. When reading the code, you don’t need to look elsewhere for the method’s definition.
  3. Run time advantages.
  4. Allows to create  delegates or expression tree types

Statement Lambdas

(input-parameters) => { statement; }+

The body of a statement lambda can consist of any number of statements; however, in practice there are typically no more than two or three.

Async Lambdas

Lambda expressions and statements can incorporate asynchronous processing by using the async and await keywords.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            // ExampleMethodAsync returns a Task.
            await ExampleMethodAsync();
            textBox1.Text += "\nControl returned to Click event handler.\n";
        };
    }  

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

instead of

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }  

    private async void button1_Click(object sender, EventArgs e)
    {
        // ExampleMethodAsync returns a Task.
        await ExampleMethodAsync();
        textBox1.Text += "\r\nControl returned to Click event handler.\n";
    }  

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
} 

===================================================

Visual Studio snippet

By default the following code snippets are included in Visual Studio: after  writing shortcut, press twice tab hardware button.

Name (or shortcut) Description Valid locations to insert snippet
#if Creates a #if directive and a #endif directive. Anywhere.
#region Creates a #region directive and a #endregion directive. Anywhere.
~ Creates a destructor for the containing class. Inside a class.
attribute Creates a declaration for a class that derives from Attribute. Inside a namespace (including the global namespace), a class, or a struct.
checked Creates a checked block. Inside a method, an indexer, a property accessor, or an event accessor.
class Creates a class declaration. Inside a namespace (including the global namespace), a class, or a struct.
ctor Creates a constructor for the containing class. Inside a class.
cw Creates a call to WriteLine. Inside a method, an indexer, a property accessor, or an event accessor.
do Creates a dowhile loop. Inside a method, an indexer, a property accessor, or an event accessor.
else Creates an else block. Inside a method, an indexer, a property accessor, or an event accessor.
enum Creates an enum declaration. Inside a namespace (including the global namespace), a class, or a struct.
equals Creates a method declaration that overrides the Equals method defined in the Object class. Inside a class or a struct.
exception Creates a declaration for a class that derives from an exception (Exception by default). Inside a namespace (including the global namespace), a class, or a struct.
for Creates a for loop. Inside a method, an indexer, a property accessor, or an event accessor.
foreach Creates a foreach loop. Inside a method, an indexer, a property accessor, or an event accessor.
forr Creates a for loop that decrements the loop variable after each iteration. Inside a method, an indexer, a property accessor, or an event accessor.
if Creates an if block. Inside a method, an indexer, a property accessor, or an event accessor.
indexer Creates an indexer declaration. Inside a class or a struct.
interface Creates an interface declaration. Inside a namespace (including the global namespace), a class, or a struct.
invoke Creates a block that safely invokes an event. Inside a method, an indexer, a property accessor, or an event accessor.
iterator Creates an iterator. Inside a class or a struct.
iterindex Creates a “named” iterator and indexer pair by using a nested class. Inside a class or a struct.
lock Creates a lock block. Inside a method, an indexer, a property accessor, or an event accessor.
mbox Creates a call to MessageBox.Show. You may have to add a reference to System.Windows.Forms.dll. Inside a method, an indexer, a property accessor, or an event accessor.
namespace Creates a namespace declaration. Inside a namespace (including the global namespace).
prop Creates an auto-implemented property declaration. Inside a class or a struct.
propfull Creates a property declaration with get and set accessors. Inside a class or a struct.
propg Creates a read-only auto-implemented property with a private “set” accessor. Inside a class or a struct.
sim Creates a staticint Main method declaration. Inside a class or a struct.
struct Creates a struct declaration. Inside a namespace (including the global namespace), a class, or a struct.
svm Creates a staticvoid Main method declaration. Inside a class or a struct.
switch Creates a switch block. Inside a method, an indexer, a property accessor, or an event accessor.
try Creates a try-catch block. Inside a method, an indexer, a property accessor, or an event accessor.
tryf Creates a try-finally block. Inside a method, an indexer, a property accessor, or an event accessor.
unchecked Creates an unchecked block. Inside a method, an indexer, a property accessor, or an event accessor.
unsafe Creates an unsafe block. Inside a method, an indexer, a property accessor, or an event accessor.
using Creates a using directive. Inside a namespace (including the global namespace).
while Creates a while loop. Inside a method, an indexer, a property accessor, or an event accessor.

===================================================

Size of both references and data types

The reference types (object references and pointers) are the size of a memory address, which would be 32 bits (4 bytes) on a 32-bit platform, and 64-bits (8 bytes) on a 64-bit platform.

All the other data types are defined by the language, not the CPU or OS.  See the reference chart below.

 

Short Name .NET Class Type Width Range (bits)
byte Byte Unsigned integer 8 0 to 255
sbyte SByte Signed integer 8 -128 to 127
int Int32 Signed integer 32 -2,147,483,648 to 2,147,483,647
uint UInt32 Unsigned integer 32 0 to 4294967295
short Int16 Signed integer 16 -32,768 to 32,767
ushort UInt16 Unsigned integer 16 0 to 65535
long Int64 Signed integer 64 -9223372036854775808 to 9223372036854775807
ulong UInt64 Unsigned integer 64 0 to 18446744073709551615
float Single Single-precision floating point type 32 -3.402823e38 to 3.402823e38
double Double Double-precision floating point type 64 -1.79769313486232e308 to 1.79769313486232e308
char Char A single Unicode character 16 Unicode symbols used in text
bool Boolean Logical Boolean type 8 True or false
object Object Base type of all other types
string String A sequence of characters
decimal Decimal Precise fractional or integral type that can represent decimal numbers with 29 significant digits 128 ±1.0 × 10e−28 to ±7.9 × 10e28

See http://msdn.microsoft.com/en-us/library/ms228360.aspx

 

Pubblicità

Informazioni su Enzo Contini

Electronic engineer
Questa voce è stata pubblicata in Smartphone OS, Windows. Contrassegna il permalink.

Lascia un Commento/Leave a comment

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.