Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Monday, July 16, 2012

Adding Attributes to Generated Classes


ASP.NET MVC 2 adds support for data annotations, implemented via attributes on your model classes.  Depending on your design, you may be using an OR/M tool like Entity Framework or LINQ-to-SQL to generate your entity classes, and you may further be using these entities directly as your Model.  This is fairly common, and alleviates the need to do mapping between POCO domain objects and such entities (though there are certainly pros and cons to using such entities directly).
As an example, the current version of the NerdDinner application (available on CodePlex atnerddinner.codeplex.com) uses Entity Framework for its model.  Thus, there is a NerdDinner.edmx file in the project, and a generated NerdDinner.Models.Dinner class.  Fortunately, these generated classes are marked as partial, so you can extend their behavior via your own partial class in a separate file.  However, if for instance the generated Dinner class has a property Title of type string, you can’t then add your own Title of type string for the purpose of adding data annotations to it, like this:
public partial class Dinner 
{
   [Required] 
   public string Title { get;set; }
}
This will result in a compilation error, because the generated Dinner class already contains a definition of Title.  How then can we add attributes to this generated code?  Do we need to go into the T4 template and add a special case that says if we’re generated a Dinner class and it has a Title property, add this attribute?  Ick.
MetadataType to the Rescue
The MetadataType attribute can be used to define a type which contains attributes (metadata) for a given class.  It is applied to the class you want to add metadata to (Dinner), and it refers to a totally separate class to which you’re free to add whatever methods and properties you like.  Using this attribute, our partial Dinner class might look like this:
[MetadataType(typeof(Dinner_Validation))] 
public partial class Dinner 
{} 
 
public class Dinner_Validation 
{ 
   [Required] 
   public string Title { get; set; } 
}
In this case the Dinner_Validation class is public, but if you were concerned about muddying your API with such classes, it could instead have been created as a private class within Dinner.  Having the validation attributes specified in their own class (with no other responsibilities) complies with the Single Responsibility Principle and makes it easy for you to test that the validation rules you expect are in place via these annotations/attributes.

Monday, April 2, 2012

Convert a generic list to DataTable in C#

The below extension method will help us to convert a generic list to DataTable


public static class DataTableExtension
{
public static DataTable ToDataTable(this List list)
{
Type type = typeof(T);
DataTable dt = new DataTable(type.Name);

var propertyInfos = type.GetProperties().ToList();

//For each property of generic List (T), add a column to table
propertyInfos.ForEach(propertyInfo =>
{
Type columnType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
dt.Columns.Add(propertyInfo.Name, columnType);
});


//Visit every property of generic List (T) and add each value to the data table
list.ForEach(item =>
{
DataRow row = dt.NewRow();
propertyInfos.ForEach(
propertyInfo =>
row[propertyInfo.Name] = propertyInfo.GetValue(item, null) ?? DBNull.Value
);
dt.Rows.Add(row);
});

//Return the datatable
return dt;
}
}




How to use this?




class Program
{
static void Main(string[] args)
{
List lstString = new List();
Enumerable.Range(1, 10).ToList().ForEach(i => lstString.Add(
new Person { PersonId = i
, PersonName = string.Concat("Name", i)
, Sex = i%2 ==0 ? "M":"F"
, Salary = 100 + i
}));

var res = lstString.ToDataTable();
}
}

public class Person
{
public int PersonId { get; set; }
public string PersonName { get; set; }
public string Sex { get; set; }
public decimal Salary { get; set; }
}












Tuesday, May 10, 2011

What is a Static Class?

Sometimes you will want to create a class that contains only static members and that cannot be instantiated. This is often the case when creating utility classes, or as an alternative to using the singleton design pattern. When using the .NET framework version 1.1, this is achieved by decorating every member declaration in the class with the "static" modifier and by including only private constructors.

In C# version 2.0, Microsoft introduced static classes to provide this behaviour using simpler code. A static class is simply a class whose definition is decorated with the "static" modifier. Once declared in this manner, the class may only contain static members. If any of the class' members is not declared as static, the compiler will report an error.

Static classes provide some benefits over standard classes. Firstly, the compiler ensures that no instance members are added accidentally. Secondly, the program can have improved performance because the overhead of creating objects is removed. However, static classes should be used with care, as they can be more difficult to mock for automated testing purposes.

A good example of the use of static classes is the Math class in the System namespace. In .NET 1.1, this was a sealed class with no public constructor. In .NET 2.0, this has been modified and is now a static class.

Creating a Static Class
To create a static class, the definition is prefixed with the "static" keyword. In the following example, the class holds a single system setting for an application. This setting holds the maximum number of files that can be used by the program and is controlled by a static property. The property is initialised in the static constructor.

public static class SystemSettings
{
static int _maximumFiles;

public static int MaximumFiles
{
get { return _maximumFiles; }
set { _maximumFiles = value; }
}

static SystemSettings()
{
_maximumFiles = 20;
}
}The members of the static class can be called without first creating an object. Instead, the name of the member is prefixed with the class name and a full stop (period), as can be demonstrated using the following code:

int maxFiles = SystemSettings.MaximumFiles;
Console.WriteLine("File limit = {0}", maxFiles); // Outputs "File limit = 20"

Tuesday, May 3, 2011

C# Named Parameters

With the introduction of C# 4.0, named parameters have been included in the language. Named parameters can be used to enhance the readability of source code and simplify some calls by specifying which parameters the argument values refer to.

What are Named Parameters?

In C# 3.0 and earlier versions, the arguments provided when calling a method would be evaluated in the order in which they appeared in the method's signature. By default, this is also the means by which argument lists are supplied in C# 4.0. However, it is now possible to associate individual arguments with specific parameters when calling a method, constructor, indexer or delegate by using named parameters.
When using a named argument, you provide the name of the parameter that you wish to pass a value to within the method call. For calls that pass literal values, this can improve the readability of your source code. Instead of viewing the method signature or displaying Intellisense for the call, the parameter names can make the literals instantly understood.
We can demonstrate this with an example. The MessageSender class below includes a single method that simulates sending a message by outputting to the console. The parameters allow some text to be provided, along with two formatting options.
class MessageSender
{
    public bool SendMessage(string message, bool useQuotes, bool capitalise)
    {
        message = capitalise ? message.ToUpper() : message;
        message = useQuotes ? string.Format("\"{0}\"", message) : message;
        Console.WriteLine(message);
        return true;
    }
}
When calling the SendMessage method without named parameters, the following code could be used:
var sender = new MessageSender();
sender.SendMessage("Hello", false, true);
At first glance, the "message" parameter is reasonably simple to understand. The effect of the two Boolean values is less easy to determine without viewing the method's signature. However, we can use named parameters for all three arguments to make their purposes obvious. This is achieved by adding the parameter name followed by a colon (:) prior to the value for each argument, as shown below:
sender.SendMessage(message: "Hello", useQuotes: false, capitalise: true);
When you are using named parameters, the arguments for a call no longer need to be passed in the order in which they appear in the member's signature. You are free to provide them in any order, allowing you to make the purpose of a call even more obvious in some situations. The following example might not improve readability but does show that the order of named arguments is unimportant to the compiler.
sender.SendMessage(capitalise: true, useQuotes: false, message: "Hello");
You can mix named and unnamed arguments in a call as long as all of the unnamed arguments appear before any named ones. The unnamed arguments will be applied in the order that they appear in the method's signature. This allows code such as the following, where the first argument's purpose is obvious but where the readability of the two Booleans is improved by the naming:
sender.SendMessage("Hello", useQuotes: false, capitalise: true);

Named Arguments with Optional Parameters

Named parameters provide more flexibility when used with optional parameters. When you make calls to members that include several optional parameters, you can omit any parameter whilst supplying values to any others. To demonstrate, adjust the test method as follows to make the two Boolean properties optional:
public bool SendMessage(string message, bool useQuotes = false, bool capitalise = false)
{
    message = capitalise ? message.ToUpper() : message;
    message = useQuotes ? string.Format("\"{0}\"", message) : message;
    Console.WriteLine(message);
    return true;
}
Calls to the above method that do not use named parameters must provide the arguments in the correct order. This would prevent you from supplying a value for the capitalise parameter whilst using the default value for useQuotes. With named parameters, this restriction is removed:

sender.SendMessage("Hello", capitalise: true);

Thursday, April 28, 2011

Using Returned XML with C#

Once you have retrieved data from a web service you will need to do something with it. This HOWTO describes the various built-in methods .NET provides to use XML returned by a web service.
  • Overview
  • Returned Data to a String
  • Using XmlReader
  • Using XmlDocument
  • Using XPathNavigator/XPathDocument
  • Using a DataSet
  • Further Reading

Overview

The .NET Framework provides excellent support for XML. Combined with the databinding support of WinForms and ASP.NET applications you have an easy and powerful set of tools. ASP.NET 2.0 takes databinding another step further by providing the DataSource control which lets you declaratively provide data access to data-bound UI controls.

Returned Data to a String

The simplest way to view the returned data is to get the response stream and put it into a string. This is especially handy for debugging. The following code gets a web page and returns the contents as a string.

C# String Sample


  1. public class StringGet   
  2. {   
  3.     public static string GetPageAsString(Uri address)   
  4.     {   
  5.         string result = "";   
  6.   
  7.         // Create the web request   
  8.         HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;   
  9.   
  10.         // Get response   
  11.         using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)   
  12.         {   
  13.             // Get the response stream   
  14.             StreamReader reader = new StreamReader(response.GetResponseStream());   
  15.   
  16.             // Read the whole contents and return as a string   
  17.             result = reader.ReadToEnd();   
  18.         }   
  19.   
  20.         return result;   
  21.     }   
  22. }   

Using XmlReader

XmlReader provides fast forward-only access to XML data. It also allows you to read data as simple-typed values rather than strings. XmlReader can load an XML document without having to use HttpRequest, though you won't have the same amount of control over the request. If you use HttpRequest, you can just pass the stream returned by the GetResponseStream() method to XmlReader. Fast write-only functions are provided by XmlTextWriter.
With .NET 2.0 you should create XmlReader instances using the System.Xml.XmlReader.Create method. For the sake of compatibility and clarity the next sample uses the .NET 1.1 creation method.

C# XmlReader Sample


  1. using System.Xml;   
  2.   
  3. // Retrieve XML document   
  4. XmlTextReader reader = new XmlTextReader("http://xml.weather.yahoo.com/forecastrss?p=94704");   
  5.   
  6. // Skip non-significant whitespace   
  7. reader.WhitespaceHandling = WhitespaceHandling.Significant;   
  8.   
  9. // Read nodes one at a time   
  10. while (reader.Read())   
  11. {   
  12.     // Print out info on node   
  13.     Console.WriteLine("{0}: {1}", reader.NodeType.ToString(), reader.Name);   
  14. }   

Using XmlDocument

XmlDocument gives more flexibility and is a good choice if you need to navigate or modify the data via the DOM. It also works as a source for the XslTransform class allowing you to perform XSL transformations.

C# XmlDocument Sample


  1. // Create a new XmlDocument   
  2. XmlDocument doc = new XmlDocument();   
  3.   
  4. // Load data   
  5. doc.Load("http://xml.weather.yahoo.com/forecastrss?p=94704");   
  6.   
  7. // Set up namespace manager for XPath   
  8. XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);   
  9. ns.AddNamespace("yweather""http://xml.weather.yahoo.com/ns/rss/1.0");   
  10.   
  11. // Get forecast with XPath   
  12. XmlNodeList nodes = doc.SelectNodes("/rss/channel/item/yweather:forecast", ns);   
  13.   
  14. // You can also get elements based on their tag name and namespace,   
  15. // though this isn't recommended   
  16. //XmlNodeList nodes = doc.GetElementsByTagName("forecast",    
  17. //                          "http://xml.weather.yahoo.com/ns/rss/1.0");   
  18.   
  19. foreach(XmlNode node in nodes)   
  20. {   
  21.     Console.WriteLine("{0}: {1}, {2}F - {3}F",   
  22.                         node.Attributes["day"].InnerText,   
  23.                         node.Attributes["text"].InnerText,   
  24.                         node.Attributes["low"].InnerText,   
  25.                         node.Attributes["high"].InnerText);   
  26. }   

Using XPathNavigator/XPathDocument

XPathDocument provides fast, read-only access to the contents of an XML document using XPath. Its usage is similar to using XPath with XmlDocument.

C# XPathDocument Sample


  1. using System.Xml.XPath;   
  2.   
  3. // Create a new XmlDocument   
  4. XPathDocument doc = new XPathDocument("http://xml.weather.yahoo.com/forecastrss?p=94704");   
  5.   
  6. // Create navigator   
  7. XPathNavigator navigator = doc.CreateNavigator();   
  8.   
  9. // Set up namespace manager for XPath   
  10. XmlNamespaceManager ns = new XmlNamespaceManager(navigator.NameTable);   
  11. ns.AddNamespace("yweather""http://xml.weather.yahoo.com/ns/rss/1.0");   
  12.   
  13. // Get forecast with XPath   
  14. XPathNodeIterator nodes = navigator.Select("/rss/channel/item/yweather:forecast", ns);   
  15.   
  16. while(nodes.MoveNext())   
  17. {   
  18.     XPathNavigator node = nodes.Current;   
  19.   
  20.     Console.WriteLine("{0}: {1}, {2}F - {3}F",   
  21.                         node.GetAttribute("day", ns.DefaultNamespace),   
  22.                         node.GetAttribute("text", ns.DefaultNamespace),   
  23.                         node.GetAttribute("low", ns.DefaultNamespace),   
  24.                         node.GetAttribute("high", ns.DefaultNamespace));   
  25. }   

Using a DataSet

Using a DataSet from the System.Data namespace lets you bind the returned data to controls and also access hierarchical data easily. A dataset can infer the structure automatically from XML, create corresponding tables and relationships between them and populate the tables just by calling ReadXml().

C# DataSet Sample


  1. using System.Data;   
  2.   
  3. public void RunSample()   
  4. {   
  5.     // Create the web request   
  6.     HttpWebRequest request    
  7.         = WebRequest.Create("http://xml.weather.yahoo.com/forecastrss?p=94704"as HttpWebRequest;   
  8.   
  9.     // Get response   
  10.     using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)   
  11.     {   
  12.         // Load data into a dataset   
  13.         DataSet dsWeather = new DataSet();   
  14.         dsWeather.ReadXml(response.GetResponseStream());   
  15.   
  16.         // Print dataset information   
  17.         PrintDataSet(dsWeather);   
  18.     }   
  19. }   
  20.   
  21. public static void PrintDataSet(DataSet ds)   
  22. {   
  23.     // Print out all tables and their columns   
  24.     foreach (DataTable table in ds.Tables)   
  25.     {   
  26.         Console.WriteLine("TABLE '{0}'", table.TableName);   
  27.         Console.WriteLine("Total # of rows: {0}", table.Rows.Count);   
  28.         Console.WriteLine("---------------------------------------------------------------");   
  29.   
  30.         foreach (DataColumn column in table.Columns)   
  31.         {   
  32.             Console.WriteLine("- {0} ({1})", column.ColumnName, column.DataType.ToString());   
  33.         }  // foreach column   
  34.   
  35.         Console.WriteLine(System.Environment.NewLine);   
  36.     }  // foreach table   
  37.   
  38.     // Print out table relations   
  39.     foreach (DataRelation relation in ds.Relations)   
  40.     {   
  41.         Console.WriteLine("RELATION: {0}", relation.RelationName);   
  42.         Console.WriteLine("---------------------------------------------------------------");   
  43.         Console.WriteLine("Parent: {0}", relation.ParentTable.TableName);   
  44.         Console.WriteLine("Child: {0}", relation.ChildTable.TableName);   
  45.         Console.WriteLine(System.Environment.NewLine);   
  46.     }  // foreach relation   
  47. }   

Creating a Simple Class in C# (2)

Instantiating the Class

Although we have not explicitly added any functionality to the class, it can now be instantiated to create objects. These objects will have the standard behaviour of all classes. To demonstrated this, return to the program code file containing the Main method. In this method we will create a new vehicle object and run its ToString method to see the results. As we have not yet defined how ToString should work, this will simply show the fully qualified name.
static void Main(string[] args)
{
    Vehicle car = new Vehicle();
    Console.WriteLine(car.ToString());  // Outputs "ClassTest.Vehicle"
}
NB: The prefix of ClassTest is simply the name of the namespace of the Vehicle class.

Adding Methods

Public Methods

Public methods are part of the class' public interface, ie. these are the methods that can be called by other objects.
  • C# Methods
  • C# Functional Methods
  • C# Method Parameters
The syntax for creating methods described in the above articles must be modified slightly to make the methods visible to external objects. To achieve this, the public keyword is used as a prefix. The following code added to the vehicle class provides a new method for pressing a vehicle's horn. Make sure that you add the code within the class' code block.
public void PressHorn()
{
    Console.WriteLine("Toot toot!");
}
To use the new method, change the code within the Main method as follows:
static void Main(string[] args)
{
    Vehicle car = new Vehicle();
    car.PressHorn();                    // Outputs "Toot toot!"
}

Private Methods

To provide for encapsulation, where the internal functionality of the class is hidden, some methods will be defined as private. Methods with a private protection level are completely invisible to external classes. This makes it safe for the code to be modified to change functionality, improve performance, etc. without the need to update classes that use the public interface. To define a method as private, the private keyword can be used as a prefix to the method. Alternatively, using no prefix at all implies that the method is private by default.
The following method of the car class is a part of the internal implementation not the public interface so is defined as being private.
private void MonitorOilTemperature()
{
    // Internal oil temperature monitoring code...;
}
To demonstrate that this method is unavailable to external classes, try the following code in the Main method of the program. When you attempt to compile or execute the program, an error occurs indicating that the MonitorOilTemperature method cannot be called due to its protection level.
static void Main(string[] args)
{
    Vehicle car = new Vehicle();
    car.MonitorOilTemperature();
}

Limitations

This article has described the creation of a basic class with public and private methods. However, every object that is generated from this class is identical, as it currently has no state. In the next article in the series, we will add properties to the class to resolve this.

Creating a Simple Class in C#

What is a Class?

The class is the fundamental building block of code when creating object-oriented software. A class describes in abstract all of the characteristics and behaviour of a type of object. Once instantiated, an object is generated that has all of the methods, properties and other behaviour defined within the class.
A class should not be confused with an object. The class is the abstract concept for an object that is created at design-time by the programmer. The objects based upon the class are the concrete instances of the class that occur at run-time. For example, the Car class will define that all cars have a make, model and colour. Only at run-time will an object be instantiated as a Red Ferrari Dino.

Creating a Class

The basic syntax for the creation of a new class is very simple. The keyword 'class' followed by the name of the new class is simply added to the program. This is then followed by a code block surrounded by brace characters {} to which the class' code will be added.
class class-name {}
To demonstrate this, we will create a new class in a new console application.

Create a Console Application

I will assume that you are using either Microsoft Visual Studio or Microsoft C# 2005 Express Edition to develop this program. Launch either of these development environments and elect to create a new project of type, "Console Application". Name the application, "ClassTest".
If you are using another development environment, follow the processes required to create a new console application.
Once the new application has been created, you should have a single code file named 'Program.cs' or similar within the new project. This should contain a class definition and a single method named 'Main'. This method is the first piece of code executed when the software runs. The class definition will be within the code block of a namespace called 'ClassTest'. We will return to this class later.

Add a New Class to the Application

Any number of classes may be added to a namespace within a single code file. However, as this would quickly lead to very large files, it is more readable to separate classes into their own files. We will now add a new class file to the project for a class that will describe vehicles.
Choose 'Add Class...' from the Project menu of Visual Studio or Microsoft C# Express Edition. You will be asked for a name for the new class. Type 'Vehicle' and click the Add button. A new class file is generated with the definition of the class already added. Note that the namespace is the same as the namespace in the original file. You can switch between files using the Solution Explorer to compare the namespaces.
Your new class definition should be similar to that below:
namespace ClassTest
{
    class Vehicle
    {
    }
}
NB: If you are not using Visual Studio, the process for adding a class file may differ slightly.