Skip to content

Lecture No. 10

Dated: 21-05-2025

Anonymous Methods

  1. Declare a delegate
  2. Write a method with a signature defined by the delegate interface
  3. Declare the event based on that delegate
  4. Write code to hook the handler method up to the delegate (this method is the anonymous method which is a method without a name)
using System;
using System.Windows.Forms;

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent(); // This line is typically present in a partial class for designer-generated code.
                              // If you're writing a simple example from scratch without the designer, you might omit it.

        Button btnHello = new Button();
        btnHello.Text = "Hello";
        btnHello.Click += delegate { // Anonymous function starts with delegate keyword
            MessageBox.Show("Hello");
        };

        Button btnGoodbye = new Button();
        btnGoodbye.Text = "Goodbye";
        btnGoodbye.Left = btnHello.Width + 5; // Position it next to the first button
        btnGoodbye.Click += delegate(object sender, EventArgs e) { // Anonymous functions with parameters
            // Cast sender to Button to get its Text property
            string message = (sender as Button).Text;
            MessageBox.Show(message);
        };

        // Add the buttons to the form's controls collection
        Controls.Add(btnHello);
        Controls.Add(btnGoodbye);
    }

    // This is typically generated by the designer.
    // If you are creating a simple self-contained example for demonstration,
    // you might not need to explicitly implement it, but it's good practice.
    private void InitializeComponent() {
        this.SuspendLayout();
        //
        // Form1
        //
        this.ClientSize = new System.Drawing.Size(300, 200); // Set a default size for the form
        this.Name = "Form1";
        this.Text = "Button Delegates Demo"; // Set a title for the form
        this.ResumeLayout(false);
    }

    // The Main method is usually in Program.cs for Windows Forms applications.
    // This is just for a self-contained example.
    [STAThread] // Important for Windows Forms applications
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

Nullable Values

We can create nullable value types by appending a question mark to a type name.

using System;

class NullableTypesDemo {
    static void Main(string[] args) {
        // Declare a nullable integer and initialize it
        int? unitsInStock = 5;

        // Declare a nullable DateTime
        DateTime? startDate;

        // Initialize startDate to the current date and time
        startDate = DateTime.Now;
        Console.WriteLine($"Start Date (initialized): {startDate}");

        // Set startDate to null
        startDate = null;
        Console.WriteLine($"Start Date (set to null): {startDate}"); // This will print an empty line or "null"

        // Demonstrating conditional assignment for nullable types
        int availableUnits;

        // Option 1: Using an if-else statement
        if (unitsInStock == null) {
            availableUnits = 0;
        }
        else {
            // Explicit cast is required to convert from nullable int? to non-nullable int
            availableUnits = (int)unitsInStock;
        }
        Console.WriteLine($"Available Units (using if-else): {availableUnits}");

        // Option 2: Using the null-coalescing operator (??) - a more concise way
        int availableUnitsConcise = unitsInStock ?? 0;
        Console.WriteLine($"Available Units (using ?? operator): {availableUnitsConcise}");

        // Example with another nullable int set to null
        int? quantity = null;
        int displayQuantity = quantity ?? -1; // If quantity is null, displayQuantity will be -1
        Console.WriteLine($"Display Quantity (with null quantity): {displayQuantity}");

        Console.ReadLine(); // Keep the console window open
    }
}

Debugging in Visual Studio

Conditional breakpoints have a hit count and when hit condition.
Pressing F5 stops execution at breakpoints.

XML

Stands for "Extended Markup Language"; is a stricter version of HTML and is used for exchanging data.

<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01"
                 xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
  <gesmes:subject>Reference rates</gesmes:subject>
  <gesmes:Sender>
    <gesmes:name>European Central Bank</gesmes:name>
  </gesmes:Sender>
  <Cube>
    <Cube time="2012-12-18">
      <Cube currency="USD" rate="1.3178"/>
      <Cube currency="JPY" rate="110.53"/>
      <Cube currency="BGN" rate="1.9558"/>
      <Cube currency="CZK" rate="25.200"/>
      <Cube currency="DKK" rate="7.4603"/>
      <Cube currency="GBP" rate="0.81280"/>
      <Cube currency="HUF" rate="288.40"/>
      <Cube currency="LTL" rate="3.4528"/>
      <Cube currency="LVL" rate="0.6961"/>
      <Cube currency="PLN" rate="4.0928"/>
      <Cube currency="RON" rate="4.4700"/>
      <Cube currency="SEK" rate="8.7378"/>
      <Cube currency="CHF" rate="1.2080"/>
      <Cube currency="NOK" rate="7.3850"/>
      <Cube currency="HRK" rate="7.5380"/>
      <Cube currency="RUB" rate="40.6850"/>
      <Cube currency="TRY" rate="2.3476"/>
      <Cube currency="AUD" rate="1.2512"/>
      <Cube currency="BRL" rate="2.7595"/>
      <Cube currency="CAD" rate="1.2972"/>
      <Cube currency="CNY" rate="8.2079"/>
      <Cube currency="HKD" rate="10.2131"/>
      <Cube currency="IDR" rate="12707.71"/>
      <Cube currency="ILS" rate="4.9615"/>
      <Cube currency="INR" rate="72.2880"/>
      <Cube currency="KRW" rate="1413.30"/>
      <Cube currency="MXN" rate="16.7795"/>
      <Cube currency="MYR" rate="4.0236"/>
      <Cube currency="NZD" rate="1.5660"/>
      <Cube currency="PHP" rate="54.068"/>
      <Cube currency="SGD" rate="1.6053"/>
      <Cube currency="THB" rate="40.285"/>
      <Cube currency="ZAR" rate="11.2733"/>
    </Cube>
  </Cube>
</gesmes:Envelope>

There are 2 methods to read XML documents.

XmlDocument

Loads the whole document in memory, lets you go backward and forward and even apply XPath searches on it.

using System;
using System.Xml; // Required for XmlDocument and XmlNode

namespace ParsingXml {
    class Program {
        static void Main(string[] args) {
            // Create a new XmlDocument instance
            XmlDocument xmlDoc = new XmlDocument();

            try {
                // Load the XML document from the specified URL
                xmlDoc.Load("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml");

                // Navigate to the specific nodes containing currency rates.
                // Based on the XML structure, this path targets the <Cube> elements within the
                // <Cube time="..."> element.
                // xmldoc.documentelement -> <gesmes:Envelope> (root)
                // .childnodes[2]       -> <Cube> (the one containing time-stamped cubes)
                // .childnodes[0]       -> <Cube time="2012-12-18"> (the first child of the above Cube)
                // .ChildNodes          -> Collection of individual <Cube currency="..."> elements
                foreach (XmlNode xmlNode in xmlDoc.DocumentElement.ChildNodes[2].ChildNodes[0].ChildNodes) {
                    // Check if the node is an element and has the expected attributes
                    if (xmlNode.NodeType == XmlNodeType.Element &&
                        xmlNode.Attributes["currency"] != null &&
                        xmlNode.Attributes["rate"] != null) {
                        // Access the "currency" and "rate" attributes and print their values
                        Console.WriteLine(xmlNode.Attributes["currency"].Value + ": " + xmlNode.Attributes["rate"].Value);
                    }
                }
            }
            catch (XmlException ex) {
                Console.WriteLine($"XML Error: {ex.Message}");
            }
            catch (Exception ex) {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }

            Console.ReadKey(); // Keep the console window open until a key is pressed
        }
    }
}

XmlReader

This takes less memory and reads one element at a time.

using System;
using System.Text;
using System.Xml;

namespace ParsingXml {
    class Program {
        static void Main(string[] args) {
            // The URL for the ECB daily exchange rates XML feed
            string xmlUrl = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml";

            // Create an XmlReader instance to read the XML from the URL
            XmlReader xmlReader = XmlReader.Create(xmlUrl);

            // Loop through the XML file node by node
            while (xmlReader.Read()) {
                // Check if the current node is an element and its name is "Cube"
                if ((xmlReader.NodeType == XmlNodeType.Element) && (xmlReader.Name == "Cube")) {
                    // Check if the "Cube" element has attributes
                    if (xmlReader.HasAttributes) {
                        // The innermost "Cube" elements have "currency" and "rate" attributes
                        // The outer "Cube" element might have a "time" attribute.
                        // We are interested in the ones with "currency" and "rate".
                        string currency = xmlReader.GetAttribute("currency");
                        string rate = xmlReader.GetAttribute("rate");

                        if (currency != null && rate != null) {
                            Console.WriteLine($"{currency}: {rate}");
                        }
                    }
                }
            }

            Console.ReadKey(); // Keep the console window open until a key is pressed
        }
    }
}

An xmlnode is derived from xmlelement and contains

  • Name
  • innertext
  • innerxml
  • outerxml
  • attributes1

XPath is a cross platform XML Query Language.

Examples

With XmlNode.SelectSingleNode()

using System;
using System.Text;
using System.Xml; // Required for XmlDocument and XmlNode

namespace ParsingXml {
    class Program {
        static void Main(string[] args) {
            XmlDocument xmlDoc = new XmlDocument();

            try {
                // Load the XML document from the specified RSS feed URL
                xmlDoc.Load("http://rss.cnn.com/rss/edition_world.rss");

                // Select a single node using an XPath expression
                // This XPath targets the 'title' element that is a child of 'channel', which is a child of 'rss'.
                XmlNode titleNode = xmlDoc.SelectSingleNode("//rss/channel/title");

                // Check if the title node was found before trying to access its InnerText
                if (titleNode != null) {
                    Console.WriteLine(titleNode.InnerText);
                }
                else {
                    Console.WriteLine("Title node not found.");
                }
            }
            catch (XmlException ex) {
                Console.WriteLine($"XML Error: {ex.Message}");
            }
            catch (Exception ex) {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }

            Console.ReadKey(); // Keep the console window open until a key is pressed
        }
    }
}

With XmlNode.SelectNodes()

using System;
using System.Text;
using System.Xml; // Required for XmlDocument and XmlNode

namespace ParsingXml {
    class Program {
        static void Main(string[] args) {
            XmlDocument xmlDoc = new XmlDocument();

            try {
                // Load the XML document from the specified RSS feed URL
                xmlDoc.Load("http://rss.cnn.com/rss/edition_world.rss");

                // Select all 'item' nodes that are children of 'channel' which is a child of 'rss'.
                XmlNodeList itemNodes = xmlDoc.SelectNodes("//rss/channel/item");

                // Iterate through each 'item' node found
                foreach (XmlNode itemNode in itemNodes) {
                    // Within each 'item' node, select the single 'title' child node
                    XmlNode titleNode = itemNode.SelectSingleNode("title");
                    // Within each 'item' node, select the single 'pubDate' child node
                    XmlNode dateNode = itemNode.SelectSingleNode("pubDate");

                    // Check if both title and date nodes were found
                    if ((titleNode != null) && (dateNode != null)) {
                        // Print the publication date and the title of the news item
                        Console.WriteLine(dateNode.InnerText + ": " + titleNode.InnerText);
                    }
                }
            }
            catch (XmlException ex) {
                Console.WriteLine($"XML Error: {ex.Message}");
            }
            catch (Exception ex) {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }

            Console.ReadKey(); // Keep the console window open until a key is pressed
        }
    }
}

Writing XML Using XmlWriter

using System;
using System.Text;
using System.Xml; // Required for XmlWriter

namespace WritingXml {
    class Program {
        static void Main(string[] args) {
            // Create an XmlWriter instance to write to "test.xml"
            // XmlWriter.Create provides options for formatting (indentation, encoding).
            // Here, we're using default settings, which often means no indentation.
            // For indented output, you might use:
            // XmlWriterSettings settings = new XmlWriterSettings { Indent = true, IndentChars = "  " };
            // XmlWriter xmlWriter = XmlWriter.Create("test.xml", settings);

            XmlWriter xmlWriter = XmlWriter.Create("test.xml");

            // Start the XML document
            xmlWriter.WriteStartDocument();

            // Write the root element <users>
            xmlWriter.WriteStartElement("users");

            // Write the first <user> element
            xmlWriter.WriteStartElement("user");
            xmlWriter.WriteAttributeString("age", "42"); // Add an attribute to <user>
            xmlWriter.WriteString("John Doe"); // Add inner text to <user>
            xmlWriter.WriteEndElement(); // Close the <user> element

            // Write the second <user> element
            xmlWriter.WriteStartElement("user");
            xmlWriter.WriteAttributeString("age", "39"); // Add an attribute to <user>
            xmlWriter.WriteString("Jane Doe"); // Add inner text to <user>
            xmlWriter.WriteEndElement(); // Close the <user> element

            // End the XML document (this automatically closes any open elements, including <users>)
            xmlWriter.WriteEndDocument();

            // Close the XmlWriter to ensure all buffered data is written to the file
            xmlWriter.Close();

            Console.WriteLine("XML file 'test.xml' created successfully.");
            Console.ReadKey(); // Keep the console window open
        }
    }
}

The above code creates the following XML.

<users>
  <user age="42">John Doe</user>
  <user age="39">Jane Doe</user>
</users>

References


  1. Read more about attributes