Wednesday, July 9, 2008

Dynamic Stylesheet Assignment Dependent on Browser

I've two stylesheets. One for Internet Explorer & other for other browsers. When the client is IE, the web page should have IE-specific stylesheet attached. For rest of the browsers, the web page must use the other stylesheet.
Demo: Get two stylesheets with body background set to two different colors.
body
{
background-color:blue;
}
body
{
background-color:black;
}

Add the following code to Page_Load event handler:
protected void Page_Load(object sender, EventArgs e)
{
HtmlLink lnk = new HtmlLink();
if (Request.Browser.Type.Contains("IE"))
{
lnk.Href = "~/StyleSheet.css";
}
else
{
lnk.Href = "~/StyleSheet2.css";
}
lnk.Attributes.Add("rel", "stylesheet");
lnk.Attributes.Add("type", "text/css");
this.Header.Controls.Add(lnk);
}
Test with Internet Explorer & some other browser like Mozilla, Opera etc.

Monday, May 26, 2008

Delegates in C#

Pointer is a variable, which stores address of some memory location. The memory location can be the storage for some value or beginning of function. When it points to function, it is function pointer. Function pointer has address of the function.

Function pointers are not safe. In thousand lines of code, if we have to invoke the function using function pointer, we cannot assure that the pointer points to function without going through the code.
We cannot ensure the number of parameters to the function or the order of parameters. Order of parameters refer to data types. What will happen if we invoked a function with function pointer & pointer is not pointing to function? What will happen if we invoked a function with function pointer & number of arguments are more or less passed? What will happen if we invoked a function with function pointer & order of parameters is wrong? (e.g. Function accepts int first & we pass string first.)

In all cases, our application will crash. In essence, Function pointers are not type-safe.

.NET has got a concept of delegates which are type-safe function pointers with ability to point to multiple functions. Delegates are declared in C# using keyword delegate.
public delegate void DisplayDelegate(string msg);

Declaration of delegate is just like function declaration. That is, the delegate must be declared with return data type & parameters. Parameter names are not relevant.

Internally, a class "DisplayDelegate" is generated which derives from System.MulticastDelegate. System.MulticastDelegate derives from System.Delegate. System.Delegate is the base class. One can create the object of "DisplayDelegate" class. The constructor accepts the function which has same signature as that of delegate declaration.
using System;

namespace DelegateDemo
{
public delegate void DisplayDelegate(string msg);
class Program
{
static void Main(string[] args)
{
DisplayDelegate del = new DisplayDelegate(Show);
del("Hello, delegate!!!");
//Or del.Invoke("Hello, delegate!!!");
}
static void Show(string str)
{
Console.WriteLine(str);
}
}
}
To invoke function using delegate, use Invoke function on delegate object with parameter values for the function. The function wrapped in delegate can be static or instance function.

Let's see, how delegates are type-safe? When one creates a delegate object, the delegate is aware of the parameters required. Wherever you call the function using delegate, compiler will not compile the program if,

  • function specified in constructor is not with appropriate function signature.
  • the number of parameters are less or more while invoking the function.
  • the order of parameters is not appropriate.
In essence, delegates are type-safe. One can catch the errors at compile-time only using delegates

A single delegate can have multiple functions. All functions must have same signature like delegate. Delegate invokes functions in FIFO(First-In,First-Out) order. If the function has return value, return value of last function invoked will be returned by delegate. Return values of all other functions are lost.

System.Delegate class has two static methods Combine and Remove. Use the methods to provide the delegate with multiple functions.
using System;
using System.Windows.Forms;

namespace DelegateDemo
{
public delegate void DisplayDelegate(string msg);
class Program
{
static void Main(string[] args)
{
DisplayDelegate del = new DisplayDelegate(Show);
DisplayDelegate del1 = new DisplayDelegate(Print);
del = (DisplayDelegate)Delegate.Combine(del, del1);
del("Hello,World!!!");
del = (DisplayDelegate)Delegate.Remove(del, del1);
del("Hi!!!");
}
static void Show(string str)
{
MessageBox.Show(str);
}
static void Print(string msg)
{
Console.WriteLine(msg);
}
}
}

System.Delegate has two properties Method and Target. The derived class have these properties inherited. "Method" property gets the method represented by delegate. "Target" gets the instance/object on which the delegate operates. "Target" returns null for static methods.
static void Main(string[] args)
{
DisplayDelegate del = new DisplayDelegate(Show);
Console.WriteLine(del.Method.Name);
if(del.Target!=null)
Console.WriteLine(del.Target.ToString());
}

If delegate has multiple functions, one can use GetInvocationList method of System.Delegate class to retrieve System.Delegate[] array.

static void Main(string[] args)
{
DisplayDelegate del = new DisplayDelegate(Show);
DisplayDelegate del1 = new DisplayDelegate(Print);
del = (DisplayDelegate)Delegate.Combine(del, del1);
foreach (DisplayDelegate minf in del.GetInvocationList())
{
Console.WriteLine(minf.Method.Name);
}
}

Wednesday, May 21, 2008

Number Flip in numeric data types

Look at the code below. It prints -128 as output. Oops!!! How?

using System;

namespace NumberFlipDemo
{
class Program
{
static void Main(string[] args)
{
sbyte i = 127;
i++;
Console.WriteLine(i.ToString());
}
}
}
Let dig out the answer.
If we look at carefully, signed byte has range from -128 to 127.
Three methods to represent negative numbers:
Signed Magnitude -->Two representations for 0; -1 repsentated as 81.
1's Complement --> Two Representation for 0; -1 represented as FE.
2'Complement --> Single Representation for 0; -1 represented as FF.
How negative numbers are represented in the machine? Let's check.See the code here.

static void Main(string[] args)
{
sbyte i = -1;
Console.WriteLine(i.ToString("x"));
//parameter "x" to ToString gives hex o/p.
}

Output is FF. Machine uses 2's complement.

How to compute 2's Complement representation?Consider we want to represent -2 in 2's complement.
Take binary representation of 2 i.e. 0000 0010. Complement all bits. Result is 1111 1101. Now add 1 to it. We will get 1111 1110 i.e. FE.

To compute 2's complement representation of a number. First complement the bits of binary representation of the number absolute.( abs(-2)=2). Add bit 1 to the complemented bits. The result is 2's complement.
Now back to our question. Why the above code snippet gives wrong o/p without any error?
Consider that size of integer is 2 bits. Hence range of numbers to be accomodated in integer data type is -2 to 1. Let put binary representation of all these numbers in a table.

1--> 01
0--> 00
-1 --> 11 (2's complement)
-2 --> 10 (2's complement)


Now if my integer variable has a extreme positive value i.e. 1 e.g. i=1;
Add 1 to i.

i+1=1+1 =>(01)+(01)=(10)=> -2
i has value 1 i.e. binary 01. Add 1 bit to it.See the result. It gives us 10 which is being binary representation for -2.

In same fashion, number flips to -128 in case of signed byte. The theory is applicable to all whole number data types i.e. byte, sbyte,int, short, long.


Be careful while making choice of data type!!! The theory applies to all programming lanaguages.

Tuesday, May 20, 2008

Extension Methods in C# 3.0

Developer code for assemblies. Compile it & publish it for client use. User of assembly may like to have some additional functionality in data types of the assembly. e.g int or Int32 do not have function to convert integer to complex number. ComplexNumber is the new data type defined by user.

Now with C# 3.0 has provided with the concept of extension methods. Extension methods enable us to extend the functionality of data types already defined. No source code of the assembly is available to modify & recompile the assembly. Still one can extend the data types functionality.

Inheritance also provides capability to extend the functionality but the extended functionality is available only for derived classes & not to the base class. e.g Consider I'd like to have a ToInt function in String class. If I use inheritance approach, I have to create new derived type. So I cannot use methods of derived type on my String objects.

Extension methods are written in static class. The method should also a static method. First parameter of the method must be of type being extended. The first parameter must have this keyword before it.

See the code below.
public static class ExtensionInt
{
public static Complex ToComplex(this int val)
{
Complex temp = new Complex();
temp.Real = val;
return temp;
}
}

Complex is the type defined as follows:

public class Complex
{
public int Real;
public int Imag;
public override string ToString()
{
return (Real.ToString() + "+i" + Imag.ToString());
}
}


Use the method ToComplex for int or Int32.
static void Main(string[] args)
{
int i = 5;
Console.WriteLine(i.ToComplex().ToString());
}

Sealed classes can take advantage of extension methods. LINQ makes use of extension methods defined in Enumerable static class. The class extends functionality of objects implementing IEnumerable interface. To use the extension methods from Enumerable class refer the assembly System.Core.

Monday, May 19, 2008

Local Type Inference in C# 3.0

C# 3.0 has new feature called "Local Type Inference". Type Inference lets compiler decide the data type of variable/object. Variable initializing data value helps compiler to decide the data type. C# 3.0 introduces new keywaord "var" to declare such variables. No explicit type declaration is required.

Local Type Inference has type inference only for local variables. One cannot declare class-/struct-level fields with keyword "var". "var" cannot act as return type for function and cannot appear in function parameter i.e. no "var" should be used in function signature.


using System;

namespace TypeInference
{
class Program
{
static void Main(string[] args)
{
var i = 5;
var intArray = new int[] { 1, 2, 3, 4, 5 };
//Variables declared with var cannot be assigned to null if no type has been inferred.
var str = default(string);
Console.WriteLine("Data Type Of i:"+i.GetType().Name);
Console.WriteLine("Data Type of intArray:" + intArray.GetType().Name);
//Console.WriteLine("Data Type of str:" + str.GetType().Name); -->Null Reference Exception
str = "";
Console.WriteLine("Data Type of str:" + str.GetType().Name);
}
}
}

Thursday, May 15, 2008

Obtaining System Information in C#

System.Windows.Forms namespace has SystemInformation class. The class has various static properties. To get information about the current system environment, use the class.

To determine the startup mode of the system, use BootMode property. The property can have values : Normal, FailSafe or FailSafeWithNetwork. All these values are defined in BootMode enumeration of System.Windows.Forms namespace.

using System;
using System.Windows.Forms;

//Add reference to System.Windows.Forms assembly.

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(SystemInformation.BootMode.ToString());
}
}
}

To access the computer name, use ComputerName property.

Console.WriteLine(SystemInformation.ComputeName);

To find out number of displays connected to machine, MonitorCount propery will help us.

Console.WriteLine(SystemInformation.MonitorCount.ToString());

Availability of mouse can be checked with the help of property MousePresent.

static void Main(string[] args)
{
if(SystemInformation.MousePresent)
Console.WriteLine("System has the mouse connected");
}

To check for network connection availability, use Network property.

if(SystemInformation.Network)
Console.WriteLine("System is connected to the network.");

There are lot many properties exposed by SystemInformation class. Check out MSDN!!!

Boxing and UnBoxing in C#

Boxing and unboxing are essential concepts of .NET type system.

Boxing refers to conversion of value type to reference type.


int i=5;
object o=i; //boxing

Unboxing refers to the conversion of reference type to value -type.


int j=(int)o; //Unboxing & type-casting.


Too much boxing and unboxing hits the application performance. Care must be taken while coding. Try to avoid boxing and unboxing.

See the below code. Does the following code has boxing?


using System;

namespace BoxingDemo
{
class Program
{
static void Main(string[] args)
{
int count = 5;
Console.WriteLine("Count:" + count);
}
}
}

Look at the IL Code generated. It has box instruction. Boxing happens here.

How to avoid it? See the code below & IL generated for it. It has no boxing.

using System;

namespace BoxingDemo
{
class Program
{
static void Main(string[] args)
{
int count = 5;
Console.WriteLine("Count:" + count.ToString());
}
}
}

Be careful!!!

Value Type & Reference Type in .NET


Object, variables; declared in .NET Compatible languages; requires data type to be specified. Data types specifies what kind of data (textual or numeric or complex) can be stored in the object/variable.

Data types in .NET are categorized in two types: Value Type and Reference Type.

Value type variables are allocated on stack & directly store the data value. Value-types cannot be assigned to null value. Value type variable vanish when they go out-of-scope (visibility).

Value types are : all primitive system types(int, float etc.) and structures, enumerations.

Reference types are allocated on heap. Value gets stored in heap. The address of memory location, having value, gets stored in stack in memory location tagged with the object/variable. Heap is garbage collected. Reference type variables/objects can be assigned null value.

Reference types: Classes, Delegates, Arrays and Interfaces

Wednesday, May 14, 2008

Union in C#

One can simulate union in C# with the help of StructLayout and FieldOffset attributes.

StructLayout attribute allows the user to control the physical layout of the data fields of a class or structure. Specify the LayoutKind the first parameter as LayoutKind.Explicit.

Tag each field with FieldOffset attribute. The attribute must be applied so that the type members are overlaying the same memory area.

using System;
using System.Runtime.InteropServices;
// Above namespace required for StructLayout attribute
namespace UnionTest
{
class Program
{
static void Main(string[] args)
{
Union test = new Union();
test.x = 256;
//Setting value 256 makes high-order byte to be set to 1. Byte ranges up to 255.
Console.WriteLine("Low:" + test.lowx + "\nHigh:" + test.highx);
}
}
[StructLayout(LayoutKind.Explicit,Size=2)]
public struct Union
{
//2 bytes
[FieldOffset(0)]public short x;
//1 byte
[FieldOffset(0)]public byte lowx;
//1 byte -->represents high-order byte.
[FieldOffset(1)]public byte highx;
}
}