Wednesday, July 29, 2009

C# Constraints on Generic Types

C# Constraints on Generic Types

When you define a generic class, you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class. If client code tries to instantiate your class by using a type that is not allowed by a constraint, the result is a compile-time error. These restrictions are called constraints. Constraints are specified by using the where contextual keyword.

Why Use Generic Constraints

If you want to examine an item in a generic list to determine whether it is valid or to compare it to some other item, the compiler must have some guarantee that the operator or method it has to call will be supported by any type argument that might be specified by client code. This guarantee is obtained by applying one or more constraints to your generic class definition. For example, the base class constraint tells the compiler that only objects of this type or derived from this type will be used as type arguments. Once the compiler has this guarantee, it can allow methods of that type to be called in the generic class. Constraints are applied by using the contextual keyword where.

You can also set up constraints on generic classes. What if you wanted to create a generic list of objects that derived from a certain base class? This would allow you call certain functions that existed in that class.
By constraining the type, you increase the number of functions you can perform on the type.
// File: Constraints.cs
using System;
public class Employee
{
private string name;
private int id;
public Employee(string name, int id)
{
this.name = name;
this.id = id;
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
}
class MyList where T : Employee
{
T[] list;
int count;
public MyList()
{
list = new T[10];
count = 0;
}
public void InsertSorted(T t)
{
int index = 0;
bool added = false;
while (index < count)
{
if (list[index].Id > t.Id)
{
for (int last = count; last > index; last--)
{
list[last] = list[last - 1];
}
list[index] = t;
added = true;
break;
}
index++;
}
if (!added)
{
list[index] = t;
}
count++;
}
}
class Program
{
static void Main()
{
MyList myList = new MyList();
myList.InsertSorted(new Employee("dan", 200));
myList.InsertSorted(new Employee("sabet", 100));
myList.InsertSorted(new Employee("mike", 150));
myList.InsertSorted(new Employee("richard", 120));
}
}

Friday, July 24, 2009

Abstract Factory Design Pattern

Design Patterns:

Design patterns make it easier to reuse successful designs and architectures. Design patterns help you choose design alternatives that make a system reusable and avoid alternatives that compromise reusability. They help make a system independent of how its objects are created, composed, and represented

Abstract Design Pattern:
An abstract factory provides an interface for creating families of related objects without specifying their concrete classes.

Sometimes one wants to construct an instance of one of a suite of classes, deciding between the classes at the time of instantiation. In order to avoid duplicating the decision making everywhere an instance is created, we need a mechanism for creating instances of related classes without necessarily knowing which will be instantiated.

Create an Abstract Factory class to answer instances of concrete classes (usually subclasses). The class of the resultant instance is unknown to the client of the Abstract Factory.

There are two types of Abstract Factory:

Simple Abstract Factory is an abstract class defining Factory methods to answer instances of concrete subclasses. The choice of which subclass to instantiate is completely defined by which method is used, and is unknown to the client.

The second form of Abstract Factory is an abstract class defining a common protocol of Factory methods. Concrete subclasses of the abstract factory implement this protocol to answer instances of the appropriate suite of classes.

Need to abstract from details of implementation of products –

1. The system shall be independent of how its constituent pieces are created, composed, and represented.
2. Need to have multiple families of products - The system shall be configured with one of multiple families of products.
3. Need to enforce families of products that must be used together - A family of related product objects is designed to be used together, and you need to enforce this constraint.
4. Need to hide product implementations and just present interfaces - You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations.

Characteristics:

1. An abstract factory is an object maker.
2. It typically can produce more than one type of object.
3. Each object that it produces is known to the receiver of the created object only by that object's interface, not by the object's actual concrete implementation.
4. The different types of objects that the abstract factory can produce are related—they are from a common family.
5. An abstract factory isolates concrete classes.
6. It makes exchanging product families easy.
7. It promotes consistency among products.
8. It supports adding new kinds of products and their families

Example:

public interface IComputerFactory
{
ICPU createCPU();
IMemory createMemory();
}

public interface ICPU
{
string GetCPUString();
}

public interface IMemory
{
string GetMemoryString();
}

//Concrete CPUA
public class CPUA : ICPU
{
public string GetCPUString()
{
return "CPUA";
}
}
//Concrete MemoryA
public class MemoryA : IMemory
{
public string GetMemoryString()
{
return "MemoryA";

}
}

public class ComputerFactoryA : IComputerFactory
{
public ICPU createCPU()
{
return new CPUA();
}
public IMemory createMemory()
{
return new MemoryA();
}
}


public class Client
{
//this is a template method; does not depend on the Concrete Factory
//and the Concrete classes

public static string BuildComputer(IComputerFactory factory)
{
ICPU cpu = factory.createCPU();
IMemory memory = factory.createMemory();
StringBuilder sb = new StringBuilder();
sb.Append(string.Format("CPU:{0}", cpu.GetCPUString()));
sb.Append(Environment.NewLine);
sb.Append(string.Format("Memory:{0}",
memory.GetMemoryString()));

return sb.ToString();

}
}

Calling Client

private void button2_Click(object sender, EventArgs e)
{
Abstract_Factory.IComputerFactory factory= new Abstract_Factory.ComputerFactoryA();
MessageBox.Show(Abstract_Factory.Client.BuildComputer(factory));
}

Wednesday, July 1, 2009

Introduction to .Net 4.0

In the past programming languages were developed to be either Object oriented or functional. But, today languages were being designed with several paradigms in mind including all best features of programming and functional capabilities.

The .net languages especially C# is no mere exception to this. The C# language has been witnessing many changes and enhancements in each version to enable the application developers of C# to utilize the real power of programming languages. Ever since, the outburst of the C# language, a .net language in 1998, with goal of creating a simple, modern, object oriented and type safe language, it has witnessed many enhancements in each release of the .net framework.


The 2.0 version of the language saw the evolution of the support for the following



1) Generics,

2) Anonymous methods,

3) Iterators,

4) Partial types and

5) Nullable types.

The 3.0 version predominantly concentrated on LINQ (Language Integrated Query) and as a side note to this LINQ, the additional features includes the following to facilitate the former:

1) Implictly Typed Local Variables.

2) Extension Methods.

3) Lambda Expressions.

4) Object and Collection Initializers.

5) Annonymous types.

6) Implicitly Typed Arrays.

7) Query Expressions and Expression Trees.

Coming to the upcoming version of C# which is 4.0 is more inspired by dynamic languages like Perl, Python and Ruby. There are both advantages and disadvantages in using both statical and dynamic languages. Some of the new features that we are going to see in the upcoming release of .net Framework in respect to C# are as described in following sections.

C# 4.0 language innovations include:

Dynamically Typed Objects.
Optional and Named Parameters.
Improved COM Interoperability.
Safe Co- and Contra-variance.


1. Let us consider this simple statically typed .NET class which calls the Add method on that class to get the sum of two integers:

Calculator calc = GetCalculator();
int sum = calc.Add(10, 20);

Our code gets all the more interesting if the Calculator class is not statically typed but rather is written in COM, Ruby, Python, or even JavaScript. Even if we knew that the Calculator class is a .NET object but we don't know specifically which type it is then we would have to use reflection to discover attributes about the type at runtime and then dynamically invoke the Add method.

object calc = GetCalculator();
Type type = calc.GetType();
object result = type.InvokeMember("Add",
BindingFlags.InvokeMethod, null,
new object[] { 10, 20 });
int sum = Convert.ToInt32(result);

If the Calculator class was written in JavaScript then our code would look somewhat like the following.

ScriptObect calc = GetCalculator();
object result = calc.InvokeMember("Add", 10, 20);
int sum = Convert.ToInt32(result);

With the C# 4.0 we would simply write the following code:

dynamic calc = GetCalculator();
int result = calc.Add(10, 20);

In the above example we are declaring a variable, calc, whose static type is dynamic. Yes, you read that correctly, we've statically typed our object to be dynamic. We'll then be using dynamic method invocation to call the Add method and then dynamic conversion to convert the result of the dynamic invocation to a statically typed integer.

You're still encouraged to use static typing wherever possible because of the benefits that statically typed languages afford us. Using C# 4.0 however, it should be less painful on those occassions when you have to interact with dynamically typed objects.


2. Another major benefit of using C# 4.0 is that the language now supports optional and named parameters and so we'll now take a look at how this feature will change the way you design and write your code.

One design pattern you'll often see as that a particular method is overloaded because the method needs to be called with a variable number of parameters.

Let's assume that we have the following OpenTextFile method along with three overloads of the method with different signatures. Overloads of the primary method then call the primary method passing default values in place of those parameters for which a value was not specified within the call to the overloaded method.

public StreamReader OpenTextFile(
string path,
Encoding encoding,
bool detectEncoding,
int bufferSize) { }

public StreamReader OpenTextFile(
string path,
Encoding encoding,
bool detectEncoding) { }

public StreamReader OpenTextFile(
string path,
Encoding encoding) { }

public StreamReader OpenTextFile(string path) { }

In C# 4.0 the primary method can be refactored to use optional parameters as the following example shows:

public StreamReader OpenTextFile(
string path,
Encoding encoding = null,
bool detectEncoding = false,
int bufferSize = 1024) { }

Given this declaration it is now possible to call the OpenTextFile method omitting one or more of the optional parameters.

OpenTextFile("foo.txt", Encoding.UTF8);

It is also possible to use the C# 4.0 support for named parameters and as such the OpenTextFile method can be called omitting one or more of the optional parameters while also specifying another parameter by name.

OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4098);

Named arguments must be provided last although when provided they can be provided in any order.


3. If you have ever written any code that performs some degree of COM interoperability you have probably seen code such as the following.

object filename = "test.docx";
object missing = System.Reflection.Missing.Value;
doc.SaveAs(ref filename,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing);

With optional and named parameters the C# 4.0 language provides significant improvements in COM interoperability and so the above code can now be refactored such that the call is merely:

doc.SaveAs("foo.txt");

When performing COM interoperability you'll notice that you are able to omit the ref modifer although the use of the ref modifier is still required when not performing COM interoperability.



With previous versions of the technologies it was necessary to also ship a Primary Interop Assembly (PIA) along with your managed application. This is not necessary when using C# 4.0 because the compiler will instead inject the interop types directly into the assemblies of your managed application and will only inject those types you're using and not all of the types found within the PIA.


4. The final language improvement that we will explore is co-variance and contra-variance and we'll begin by exploring co-variance with .NET arrays.

string[] names = new string[] {
"Anders Hejlsberg",
"Mads Torgersen",
"Scott Wiltamuth",
"Peter Golde" };

Write(names);

Since version 1.0 an array in the .NET Framework has been co-variant meaning that an array of strings, for example, can be passed to a method that expects an array of objects. As such the above array can be passed to the following Write method which expects an array of objects.

private void Write(object[] objects)
{
}

Unfortunately arrays in .NET are not safely co-variant as we can see in the following code. Assuming that the objects variable is an array of strings the following will succeed.

objects[0] = "Hello World";

Although if an attempt is made to assign an integer to the array of strings an ArrayTypeMismatchException is thrown.

objects[0] = 1024;

In both C# 2.0 and C# 3.0 generics are invariant and so a compiler error would result from the following code:

List names = new List();

Write(names);

Where the Write method is defined as:


Generics with C# 4.0 now support safe co-variance and contra-variance through the use of the in and out contextual keywords. Let's take a look at how this changes the definition of the IEnumerable and IEnumerator interfaces.

public interface IEnumerable
{
IEnumerator GetEnumerator();
}

public interface IEnumerator
{
T Current { get; }
bool MoveNext();
}

You'll notice that the type parameter T of the IEnumerable interface has been prefixed with the out contextual keyword. Given that the IEnumerable interface is read only, there is no ability specified within the interface to insert new elements with the list, it is safe to treat something more derived as something less derived. With the out contextual keyword we are contractually affirming that IEnumerable is safely co-variant. Given that IEnumerable is safely co-variant we can now write the following code:


Because the IEnumerable interface uses the out contextual keyword the compiler can reason that the above assignment is safe.

Using the in contextual keyword we can achieve safe contra-variance, that is treating something less derived as something more derived.

public interface IComparer
{
int Compare(T x, T y);
}

Given that IComparer is safely contra-variant we can now write the following code:

IComparer[object] objectComparer = GetComparer();
IComparer[string] stringComparer = objectComparer;

Although the current CTP build of Visual Studio 2010 and the .NET Framework 4.0 has limited support for the variance improvements in C# 4.0 the forthcoming beta will allow you to use the new in and out contextual keywords in types such as IComparer. The .NET Framework team is updating the types within the framework to be safely co- and contra-variant.
Locations of visitors to this page