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

 

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

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 < nodo.Count; i++) {
  var myChild= nodo.Item(i);
  for (int j = 0; j < 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);  
    }  
} 
Annunci

Informazioni su Enzo Contini

Electronic engineer
Questa voce è stata pubblicata in Windows, Windows Phone/Mobile. 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 WordPress.com

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

Foto Twitter

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

Foto di Facebook

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

Google+ photo

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

Connessione a %s...