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
- Async void is for top-level event-handlers only, and event-like things. Don’t use it elsewhere in your code.
- It’s crucial to distinguish CPU-bound work (should be done on threadpool) from IO-bound work (which needn’t).
- 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.
- 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:
- Reduced typing. No need to specify the name of the function, its return type, and its access modifier.
- When reading the code, you don’t need to look elsewhere for the method’s definition.
- Run time advantages.
- 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
- Default Code Snippets
- Code Snippet Functions
- Code Snippets
- How to: Create a New Snippet with Replacements
- Template Parameters
- How to: Use Surround-with Code Snippets
- How to: Restore C# Refactoring Snippets
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