Você está na página 1de 44

Introducing C# 2.

With the release of Visual Studio 2005 (formerly codenamed Whidbey), C# is


back with some new innovations. The C# language has been updated to version 2.0
and comes with several language extensions which we will explore in this 2 part
series article. Besides Generic types, the C# language introduces some other
interesting features such as Iterators, Partial Classes and Anonymous methods,
which are briefly mentioned below.

Generics
Although new to the .NET platform, this concept has been around for years. Generics
is a term used to describe generic types. It greatly enhances application performance
and type safety and allows you to write highly general, flexible and safe code. It
permits classes, interfaces, structs, delegates and methods to be parameterized by
the types of data they store and manipulate.

Iterators
Iterators specify how a for-each loop will iterate over a collection and return its
internal items. They allow you to create enumerable classes with minimum coding.

Partial Classes
Partial Classes allows you to split a single type, like your class, across more than one
file (.cs). They are useful if you have extremely large, unwieldy types.

Nullable Types
Nullable types allow a variable to contain a value that is undefined. This is useful
when working with databases where the value returned might be null

Anonymous Methods
Anonymous Methods Are Inline Delegates. It enables you to pass a block of code as
a parameter. Anonymous methods enables you to directly associate a block of code
statements to a given event. You use them anywhere a delegate is used . So there is
no need to define a new method.

Namespace alias qualifier


C# 2.0 adds the namespace alias qualifier, the :: operator, to provide more control
over accessing namespace members.

Static Classes
With C# 2.0, now you also can declare classes as static. This signals the compiler
that this class should not be instantiated and can only contains static members.
Property Accessor Accessibility
C# 2.0 allows a fine control over the accessibility of accessors and indexers within a
property.

Covariance and Contravariance in Delegates


The method passed to a delegate may now have greater flexibility in its return type
and parameters.

Conclusion
In this article, we explored the various new features introduced in C# 2.0. In Part
two, we will explore these new features in detail.

Generics

Classes are templates that you can use to build new objects. Generics are templates
that you can use to build new classes. This code template can be applied to use the
same code repeatedly. A generic class is tied to one or more specific data types.

Generics permit classes, interfaces, structs, delegates and methods to be


parameterized by the types of data they store and manipulate. They are Type-
independent algorithms and collections. They enable programmers to achieve a high
level of code reuse and enhanced performance for collection classes. Generics are
defined with left and right brackets: <T>. Here ‘T’ in <T> is the name of the type
that is going to be used.

Let me demonstrate the use of Generics by taking a simple example:


namespace GenericsDemo
{
class TestGenerics
{
static void Main(string[] args)
{

GenericsExample();
}
private void GenericsExample()
{
ClsGeneric<int> intGeneric = new ClsGeneric<int>(1000);
ClsGeneric<string> strGeneric = new
ClsGeneric<string>("Voila");
ClsGeneric<float> fGeneric = new ClsGeneric<float>(23.38f);
ClsGeneric<double> dGeneric = new ClsGeneric<double>(444.4);
ClsGeneric<bool> bGeneric = new ClsGeneric<bool>(true);

}
}

public class ClsGeneric<T>


{
public ClsGeneric(T Type)
{
Console.WriteLine("T over here is {0} ", typeof(T).ToString());
}
}
}

By using a generic type parameter T, you can write a single class that other client
code can use without incurring the cost or risk of runtime casts or boxing operations.

Iterators

In the earlier versions of C#, in order to use the for-each loop, you need to
implement the IEnumerable interface which in turn demands the implementation of
the GetEnumerator() method. This method returns an IEnumerator object using
which you can use the foreach loop.

An iterator on the other hand, enables you to support foreach iteration in a class or
struct without having to implement the entire IEnumerable interface.
Let me demonstrate this with an example :
public class StringCollection : System.Collections.IEnumerable
{
string[] names = { "Tom", "Dick", "Harry”, "Ralph", "Jack", "Jill” };

public System.Collections.IEnumerator GetEnumerator()


{
for (int i = 0; i < names.Length; i++)
{
yield return names[i];
// In C#1.x you would have specified it using
// return names[i].GetEnumerator();
}
}
}

class TestStringCollection
{
static void Main()
{
// Create an instance
StringCollection strNames = new StringCollection();

foreach (string name in strNames)


{
System.Console.WriteLine(name);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
Note: The new iterator pattern in C# 2.0 is significantly faster than its C# 1.x
counterparts.

Partial Classes

C# 2.0 introduces the concept of partial type definitions for classes, structs, and
interfaces that allows you to define a C# type across multiple *.cs files. This leads to
easier maintenance and development as more than one developer can
simultaneously write the code for the class.

public partial class A


{
public void methodA()
{
// Code for methodA
}
}

public partial class A


{
public void methodB()
{
// Code for methodB
}
}

Nullable Types

A type is said to be nullable if it can be assigned a value or can be assigned a null


reference. This change makes it easier to integrate with databases, especially for
fields that are optional.

A null type is very similar to its equivalent non-nullable type. The difference lies in
how it is declared. For example : To declare an integer, you would declare it like
this :

int iVal = 1;

However in order to enable iVal to store a null value, you will declare it like this :

int? iVal = 1;

Now the way to define any valuetype as a nullable type is to define the generic
System.Nullable<T> type. So the syntax to define a nullable integer is:
System.Nullable<int> iVal;

However this is somewhat difficult to read and that is why C#

provides a cleaner syntax for the nullable type by adding a

question mark to the immediate right of the type name when

defining a variable. The Syntax is [Value-Type]?

So System.Nullable<int> iVal and int? iVal are equivalent.


Similarly you can also assign it a value null and use the HasValue and Value read-
only properties to test for null and retrieve the value. Here’s an example :

int? iVal = null;


if (iVal.HasValue == true)
{
System.Console.WriteLine("iVal = " + iVal.Value);
}
else
{
System.Console.WriteLine("iVal = Null");
}

Anonymous Methods

Anonymous methods help you reduce the coding overhead in instantiating delegates,
by eliminating the need to create a separate method. This construct allows you to
directly associate a block of code statements to a given event. In general, you can
use anonymous methods anywhere you can use a delegate. An anonymous method
consists of the keyword delegate, an optional parameter list, and a statement list
enclosed in { and } delimiters. In some cases, the anonymous methods can omit the
parameter list.

public class frmOld : Form


{

// This method connects the event handler.


public frmOld()

InitializeComponent();

btnOld.Click += new EventHandler(ButtonClick);

// This is the event handling method.


private void ButtonClick(object sender, EventArgs e)

MessageBox.Show("Old method of handling ButtonClick");

}
}

Using Anonymous methods :

public class frmNew : Form


{

public frmNew()
{

InitializeComponent();

btnNew.Click += delegate(object sender, EventArgs e)


{
MessageBox.Show(“New way of handling button click using
anonymous methods");
};
}
}
// Declare a delegate
delegate void PrintHello(string str);

class TestAnonymous
{
static void Main()
{

hello = new PrintHello(TestAnonymous.TestMethod);


Without anonymous method you would associate the delegate with a named method.
For eg:

hello = new PrintHello(TestAnonymous.TestMethod);

//and declared a method to associate it with the named delegate

static void TestMethod(string test)


{
System.Console.WriteLine(test);
}

Static Classes
Static classes are classes that contain only static members. These static members
can be initialized only by using static constructors. The data and functions that these
classes create, can be accessed without creating an instance of the class. Static
classes are sealed so they can not be inherited. TheSystem.Math class is an example
of this construct.

Static classes can be used when there is no data or behavior in the class that
depends on object identity. One of the advantages of static classes is improved
performance. Since there is no instantiation of object, the framework maintains a
single object in memory for static members. They are loaded automatically by the
.NET Framework common language runtime (CLR) when the program or namespace
containing the class is loaded.

Creating a static class is much the same as creating a class that contains only static
members and a private constructor. A private constructor prevents the class from
being instantiated. Lets see an example of a static class.

Property Accessor Accessibility

Properties provide flexibility to read and write the values of private fields. They can
be used as though they are public data members, but they are actually special
methods called accessors. This enables data to be accessed easily while still
providing the safety and flexibility of methods.
In C# 1.x, we declare a property in our class in the following manner:
class ClsProp
{
private string strMyName = "Suprotim";

public string StrMyName


{
get { return strMyName; }
set { strMyName = value; }
}
}
Here the ‘get’ and the ‘set’ accessors have the same accessibility level i.e., they are
both ‘public’ as the property itself is ‘public’. However, it is sometimes useful to
restrict access to one of these accessors, which was not possible for us in C# 1.x.
In C# 2.0, this has changed :
public string StrMyName
{
get
{
return strMyName;
}
protected set
{
strMyName = value;
}
}

In this example, a property called StrMyName defines a get and set accessor. The
get accessor receives the accessibility level of the property itself, public in this case,
while the set accessor is explicitly restricted by applying the protected access
modifier to the accessor itself.
Note : This feature of having Accessor Accessibility was provided in C# v1.0 beta.
However Microsoft removed it before the C# v1.0 RTM as they felt it was too
complicated for developers. In C# 2.0, it has been re-introduced.

Covariance and Contravariance

In .NET 1.1, delegates could only be created with methods whose arguments strictly
matched the signature of that delegate. With .NET 2.0, Covariance and
contravariance provide a degree of flexibility when matching delegate methods with
delegate signatures.

Delegate is type which holds the method(s) reference in an object.


it is also reffered as a type safe function pointers.

Advantages:
.Encapsulating the method's call from caller
.Effective use of Delegat improves the performance of application.
.used to call a method asynchronously.

Declaration:

public delegate type_of_delegate delegate_name()

Example : public delegate int mydelegate(int delvar1,int delvar2)

Note:
.you can use delegeate without parameter or with parameter list
.you should follow the same syntax as in the method
(if you are reffering the method with two int parameters and int return type the delegate
which you are declaring should be the same format.This is how it
is reffered as type safe function pointer)

Sample Program using Delegate :

public delegate double Delegate_Prod(int a,int b);

class Class1
{

static double fn_Prodvalues(int val1,int val2)


{
return val1*val2;
}
static void Main(string[] args)
{

//Creating the Delegate Instance


Delegate_Prod delObj = new Delegate_Prod(fn_Prodvalues);

Console.Write("Please Enter Values");

int v1 = Int32.Parse(Console.ReadLine());
int v2 = Int32.Parse(Console.ReadLine());

//use a delegate for processing

double res = delObj(v1,v2);


Console.WriteLine ("Result :"+res);
Console.ReadLine();

}
}

Explanation:

Here I have used a small program which demonstrates the use of delegate.

The delegate "Delegate_Prod" is declared with double return type and which accepts only
two integer parameters.

Inside the Class the method named fn_Prodvalues is defined with double return type and
two integer parameters.(The delegate and method is having the same signature and
parameters type)

Inside the Main method the delegate instance is created and the function name is passed
to the
delegate instance as following.

Delegate_Prod delObj = new Delegate_Prod(fn_Prodvalues);


After this we are accepting the two values from the user and passing those values to the
delegate as we do using method .

delObj(v1,v2);

Here delegate object encapsulates the method functionalities and return the result as we
specified
in the method.

Multicast Delegate
What is Multicast Delegate? :
It is a Delegate which holds the reference of more than one methods.
Multicast delegates must contain only methods that return void, else there is a run-time
exception.

Simple Program using Multicast Delegate


----------------------------------------

delegate void Delegate_Multicast(int x, int y);

Class Class2

{
static void Method1(int x, int y) {
Console.WriteLine("You r in Method 1");
}
static void Method2(int x, int y) {
Console.WriteLine("You r in Method 2");
}
public static void Main()
{
Delegate_Multicast func = new Delegate_Multicast(Method1);

func += new Delegate_Multicast(Method2);


func(1,2); // Method1 and Method2 are called
func -= new Delegate_Multicast(Method1);
func(2,3); // Only Method2 is called
}

Explanation:
In the above example you can see that two methods are defined named method1 and
method2 which takes two integer parameters and return type as void.

In the main method the Delegate object is created using the following statement

Delegate_Multicast func = new Delegate_Multicast(Method1);

Then the Delegate is added using the += operator and removed using -= operator.

#2 is right and gave acurate definition of event and event handler but since we declare a
event using delegate so we usually say a event is a delegate but from the declaration we
can see what is a delegate is the eventhandler.

Delegates are similar to function pointers of C++, they hold the address of a function,
they hide the actual information.
.Net supports 2 types of delegates:
1)Single Cast Delegate
2)Multi Cast Delegate

Multi Cast Delegate holds the addresses of more than one function.

YES,two delegates can refer the same function i.e,two delegates can hold the address of
same method.

multiple delegates and multicast delegates both are diffrent terms with diffrent aspects.
delegate having one property that it could have multiple delegates in it.it means single
delegates contain multiple delegates definition while
in other case multicast delagates means single delagates contain refrence of several
methods......

lass Design. Below is a set of birds and movements they can perform.
Birds:
Penguin:
• hopping: moves 2 ft
• flying: can't fly
Hawk:
• hopping: can't hop
• flying: moves 100 ft; won't fly if World.windSpeed > 40
Robin:
• hopping: moves 1 ft; won't hop if World.temperature < 0
• flying: moves 20 ft; won't fly if World.windSpeed > 20
Crow:
• hopping: moves 1 ft; won't hop if World.temperature < 0
• flying: moves 30 ft; won't fly if World.windSpeed > 25
Requirements:
• Create a class or set of classes in C# to represent the birds.
• Create an instance of each type of bird and add them all into a single collection. Have
each bird hop and then fly in turn, each time after the World changes. After all birds have
moved, print out the total distance that each one has moved. (See the comments in Main
below marked // TODO).
• Fill in main() to generate the desired output (which is shown under main() below).
• Use best design practices. The priority is to create maintainable code.

using System;
using System.Collections.Generic;

namespace PCD
{

public class World


{
public static int temperature = 0; // celcius
public static int windSpeed = 0; // miles per hour
}

public class MainClass


{
static void Main(string[] args)
{
// TODO: create the birds here

World. = 20;
World. temperature windSpeed = 12;

// TODO: have each bird fly & hop

// a storm arrives!
World.temperature = -10;
World.windSpeed = 30;

// TODO: have each bird fly & hop

// TODO: print total distances

}
}
}

Desired output:
The penguin moved 4 ft.
The hawk moved 200 ft.
The robin moved 21 ft.
The crow moved 31 ft.

Yes,It is possible to have different access modifiers,but the best approach is to use all
access modifiers as public for efficient data retrieval.
public String EMPNO
{
get
{
return _empno;
}
set
{
_empno = value;
}
}

I think the right answer is No, if I understand the question correctly.

We don't specify any access modifiers on "get" and "set" individually, rather we specify
on the wrapping property name.

in other words following is valid:


private int m_myInt = -1;
public int MyProperty
{
get {return m_myInt;}

set {m_myInt = value;}


}
However following is not valid
private int m_myInt = -1;
public int MyProperty
{
public get{return m_myInt;}

private set{m_myInt = value;}


}

It is very easy, if you are using .NET Framework 2.0 or above. See
http://msdn.microsoft.com/en-us/library/75e8y5dd(VS.80).aspx

In short, the restricion is always to a more restrictive level, and only one accessor can be
modified - for instance:
public int MyInt
{
get
{ return m_MyInt; }
private set
{ m_MyInt = value; }
}

will compile, but:

private int MyInt


{
get
{ return m_MyInt; }
public set
{ m_MyInt = value; }
}
will not compile, nor will:

public int MyInt


{
protected get
{ return m_MyInt; }
private set
{ m_MyInt = value; }
}
ef Parameter: Used to pass a parameter as a reference so that the function called will set
the value. This could be used to return more than 1 value by a function.
e.g.

 public int AddMuliply( int a , int b, ref int c)


Â{
  c = a*b;
  return ( a+b);
Â}
Â
The above function, returns the addition of two numbers as well as computes the
multiplication result and passes to the calling function.
Out Parameter: Used to pass values from the aspx Code-behind to the aspx page.

Correct me if I am wrong.

What is the difference between Cast and Convert

int i1 = 5;
double d1 = i1 + 0.99;
int i2 = (int)d1; //result is 5
i2 = Convert.ToInt32(d1);//result is 6

Why does cast and convert in above example have different results.

RE: what is .net Attrubute

.NET Attributes provide the means for a developer to add meta-data that describes, or
annotates, specific elements of code such as classes, methods, properties, etc. At compile
time, the resulting metadata is placed into the Portable Executable (PE)file, along with
the Microsoft Intermediate Language (MSIL). Once metadata is in the PE, other .NET
programs may access it using the .NET Reflection API
Serialization :------------------Serialization in .NET allows the programmer to take an
instance of an object and convert it into a format that is easily transmittable over the
network, or even stored in a database or file system. This object will actually be an
instance of a custom type, including any properties or fields you may have set. A few
examples I can think of include the ability to send an instance of your object to another
portion of a local or remote application, such as over a Web service. Another example of
when to choose to serialize objects is for data within objects that would normally be
stored in a database, but these pieces of data do not need to be stored individually (their
own fields in your tables). Streamline the database design by only holding those pieces of
data for each record you need to query on, and the rest of the pieces can simply be
serialized within a custom type and stored as a complete object within the
database.Advantages of Binary Serialization --------------------------------------------All
members, no matter if they are read-only will be serialized. Greater performance*
Advantages of XML Serialization -------------------------------------------Greater flexibility
of object sharing and usage (interoperability) No strict binary dependence Human
readable #region Binary Serializerspublic static System.IO.MemoryStream
SerializeBinary(object request)

INDEXER IN C#:

In c# introduce new concept is Indexer. This is very useful for some situation. Let as
discuss something about Indexer.
• Indexer Concept is object act as an array.
• Indexer an object to be indexed in the same way as an array.
• Indexer modifier can be private, public, protected or internal.
• The return type can be any valid C# types.
• Indexers in C# must have at least one parameter. Else the compiler will
generate a compilation error.

this [Parameter]
{
get
{
// Get codes goes here
}
set
{
// Set codes goes here
}
}

For Example:

using System;
using System.Collections.Generic;
using System.Text;

namespace Indexers
{
class ParentClass
{
private string[] range = new string[5];
public string this[int indexrange]
{
get
{
return range[indexrange];
}
set
{
range[indexrange] = value;
}
}
}

/* The Above Class just act as array declaration using this pointer */

class childclass
{
public static void Main()
{
ParentClass obj = new ParentClass();

/* The Above Class ParentClass create one object name is obj */

obj[0] = "ONE";
obj[1] = "TWO";
obj[2] = "THREE";
obj[3] = "FOUR ";
obj[4] = "FIVE";
Console.WriteLine("WELCOME TO C# CORNER HOME PAGE\n");
Console.WriteLine("\n");

Console.WriteLine("{0}\n,{1}\n,{2}\n,{3}\n,{4}\n", obj[0], obj[1], obj[2],


obj[3], obj[4]);
Console.WriteLine("\n");
Console.WriteLine("ALS.Senthur Ganesh Ram Kumar\n");
Console.WriteLine("\n");
Console.ReadLine();
}
}
}

All indexers should accept at least one parameter. Indexers cannot be static. This is
because static methods do not have access to ‘this’. The ‘this’ keyword indicates an
instance of the current class.
Interface:
-- If your child classes should all implement a certain group of methods/functionalities,
but each of the child classes is free to provide its own implementation, then use
interfaces.
For e.g., if you are implementing a class hierarchy for vehicles, implement an interface
called "Vehicle", which has properties like Colour, MaxSpeed etc., and methods like
Drive(). All child classes like "Car", "Scooter", "AirPlane", "SolarCar" etc. should derive
from this base interface, but provide a seperate implementation of the methods and
properties exposed by Vehicle.
-- If you want your child classes to implement multiple, unrelated functionalities, in short
multiple inheritance, use interfaces.
For e.g., if you are implementing a class called "SpaceShip", that has to have
functionalities from a "Vehicle", as well as that from a "UFO", then make both "Vehicle"
and "UFO" as interfaces, and then create a class "SpaceShip" that implements both
"Vehicle" and "UFO".
Abstract Classes
-- When you have a requirement where your base class should provide default
implementation of certain methods, whereas other methods should be open to being
overridden by child classes, use abstract classes.
For e.g., again take the example of the "Vehicle" class above. If we want all classes
deriving from "Vehicle" to implement the "Drive()" method in a fixed way, whereas the
other methods can be overridden by child classes. In such a scenario, we implement the
"Vehicle" class as an abstract class with an implementation of "Drive", while leave the
other methods / properties as abstract so they could be overridden by child classes.
-- The purpose of an abstract class is to provide a common definition of a base class that
multiple derived classes can share. For example, a class library may define an abstract
class that is used as a parameter to many of its functions, and require programmers using
that library to provide their own implementation of the class by creating a derived clas

If we have 2 interfaces, say Ix and Iy, and also we have one method in both interfaces
with same signature. Now we have to inherit a class from both interfaces so how to
access the method of interface Ix or that of Iy.

Example
interface lx
{
void Amit();
}
interface ly
{
void Amit();
}
class Dwivedi:lx,ly
{
public static void main()
{
lx k;
ly l;
k.Amit();
l.Amit();
}
}
That's the right example we can use for implementing both interfaces

An abstraction refers to how a given problem is represented in the program space.


Object-oriented languages enable you to declare classes whose names and interfaces
closely mimic real-world problem domain entities such that using the objects have a more
natural "feel" to them.

· Inheritance relates to the programmer's ability to specify that one class have a kind-
of relationship with another class. A derived class should require no more and promise no
less than its base class on any inherited interfaces. When a programmer has a reference to
a derived class, the programmer can always treat that class as though it is the base class.
This is called upcasting.

· Managed code is just code that is running under the guidance of the CLR and is
therefore being managed by the CLR. In a managed code environment, a number of rules
are in place to ensure that all applications behave in a globally uniform manner,
regardless of the language they were written in.
· To make it easy for language writers to port their languages to .NET, Microsoft
developed a language akin to assembly language called Microsoft intermediate language
(MSIL). To compile applications for .NET, compilers take source code as input and
produce MSIL as output. MSIL itself is a complete language that you can write
applications in.

· In a .Net PE file (Assembly), the operating system can't execute the MSIL code, so
from the entry point, it jumps to the _ CorExeMain function in mscoree.dll. The _
CorExeMain function starts the execution of the MSIL code that was placed in the PE.

· Three different JITters can be used to convert the MSIL into native code, depending
on the circumstances:

1. Install-time code generation: It will compile an entire assembly into CPU-specific


binary code, just as a C++ compiler does. An assembly is the code package that's sent to
the compiler.

2. JIT: The default JITter is called at run time -each time a method is invoked for the first
time.

3. EconoJIT: Another run-time JITter, the EconoJIT is specifically designed for systems
that have limited resources—for example, handheld devices with small amounts of
memory. It uses code pitching. Code pitching allows the EconoJIT to discard the
generated, or compiled, code if the system begins to run out of memory. The benefit is
that the memory is reclaimed. However, the disadvantage is that if the code being pitched
is invoked again, it must be compiled again as though it had never been called.

· In addition to mapping source code to MSIL instruction sequences, CLS-compliant


compilers have another equally important task: embedding metadata into the resulting
EXE.

· The means by which the metadata of an assembly is queried is called reflection.


Tools such as Visual Studio.NET use these reflection methods to implement features
such as IntelliSense. Another incredibly useful .NET tool that takes advantage of
reflection is the Microsoft .NET Framework IL Disassembler (ILDASM).

· Unmanaged code is code that is not controlled by the .NET runtime. This code is
still run by the .NET runtime. However, unmanaged code doesn't have the advantages
that managed code has, such as garbage collection, a unified type system, and metadata.
When you want to call COM components by managed code, you do this by creating a
.NET wrapper for the COM component so that the managed client thinks it's working
with a .NET class. And when a COM component wants to call a .NET component, it's
solved using a reciprocal approach: a COM client is fooled into thinking it's using a COM
server, which is actually a .NET service of some sort.

· Creating Alias For The Classes In A Name Space

using output = System.Console;

output.WriteLine("Hello, World");

· Viewing Assembly Code (MSIL) Of An Exe/DLL

In the Start menu's Run dialog box, type ildasm and click OK. You'll see a nondescript
application with a few menu options. At this point, from the File menu, click Open and
specify the .Net assembly (Exe/DLL). To tell whether an EXE or DLL is managed,
attempt to open it with ILDASM. If the file is a valid managed file, it will be opened. If
it's not, you'll receive an error message stating that <your file> has no valid CLR header
and cannot be disassembled

· Hungarian Notation: Hungarian notation specifies that a prefix be added to each


variable to indicate its type.

· CTS is responsible for defining the types that can be used across .NET languages.
The CTS separate types into two categories. Value types (Primitive type) and reference
types. Variables of value types are stored in the stake and variables of reference types are
stored on the heap. Value types variables cannot be null but the reference types variables
can be. Reference types are type-safe pointers. All types are ultimately derived from
System.Object type.

· Boxing is the conversion of a value type to a reference type. Unboxing is the


conversion of a reference type to a value type.

int foo = 42; // Value type.

object bar = foo; // foo is boxed to bar.

int foo2 = (int)bar; // Unboxed back to int.

When converting from a value type to a reference type—there is no explicit cast needed.
However, when unboxing—the cast is needed. This is because in the case of unboxing,
an object could be cast to any type. Therefore, the cast is necessary so that the compiler
can verify that the cast is valid per the specified variable type.

· CTS Types and Aliases

CTS Type Name

C# Alias

Description

System.Object

object

Base class for all CTS types

System.String
string

String

System.SByte

sbyte

Signed 8-bit byte (1 byte)

System.Byte

byte

Unsigned 8-bit byte (1 byte)

System.Int16

short

Signed 16-bit value (2 bytes)

System.UInt16

ushort

Unsigned 16-bit value (2 bytes)

System.Int32

int

Signed 32-bit value (4 bytes)


System.UInt32

uint

Unsigned 32-bit value (4 bytes)

System.Int64

long

Signed 64-bit value (8 bytes)

System.UInt64

ulong

Unsigned 64-bit value (8 bytes)

System.Char

char

16-bit Unicode character (2 bytes)

System.Single

float

IEEE 32-bit float (4 bytes)

System.Double

double
IEEE 64-bit float (8 bytes)

System.Boolean

bool

Boolean value (true/false)

System.Decimal

decimal

128-bit data type exact to 28 or 29 digits—mainly used for financial applications where a
great degree of accuracy is required. (16 bytes)

· Upcasting (where a derived class object is assigned to a base class object) is


implicit and legal in C# but the reverse or downcasting is not implicit and illegal in C#. If
you try to downcast the objects explicitly, no compilation error occurs, but a run-time
exception system.InvalidCastException would be there. If you downcast the objects using
'As' keyword like : <DerivedClass> c = e as <DerivedClass>, where e is a object of base
class, no compilation or run-time error would be there, instead object c would be assign
to null in case of invalid casting.

· C# Access Modifiers

Public

Member is accessible from outside the class's definition and hierarchy of derived classes.

Protected

The member is not visible outside the class and can be accessed by derived classes only.

Private
The member cannot be accessed outside the scope of the defining class.

Internal

Member is accessible within the current assembly.

· Command-Line Parameters

public static void Main(string[] args)

· C# included a mechanism by which you can define more than one class with a Main
method. To specify which Main() method to call at compilation you can use [csc
MultipleMain.cs /main:<ClassName>] switch.

· Calling Base Class Constructor

class B : A

public B() : base()

}
}

· Constants: First, a constant is a member whose value is set at compilation time,


either by the programmer or defaulted by the compiler. Second, a constant member's
value must be written as a literal. By default const members are static.

public const double pi = 3.14;

· Read-Only Fields: When you define a field with the readonly keyword, you have
the ability to set that field's value in one place: the constructor. The read-only fields that
we defined are instance fields.

public readonly int ScreenWidth;

· Static Constructors: Static constructors are constructors that are used to initialize
static fields, read-only or otherwise.

· In case of inheritance, the base class's constructor cannot be inherited. Each class
must implement its own constructor irrespective of its base class.

· An abstract class cannot be used as a sealed class.

· Passing Parameters By Reference (Like C++ Pointers)

Function Definition:
public void GetName(ref int age)

Function Calling:

int age;

Object.GetName(ref age);

When you use the ref keyword, you must initialize the passed arguments before calling
the method.

Out Keyword: Use 'Out' keyword in place of 'ref' and you would not required to initialize
the passed arguments before calling the method.

· In case of overloading, it's not sufficient to have only return type different, but
method's argument list must be different.

· Variable Method Parameters

public void GetName(params string[] s)

}
Function Calling:

string a;

string b;

Object.GetName(a,b);

use GetLength() method of passed param array to find out number of elements sent.

· Overriding: Use 'new' keyword in derived class method when you are going to
override the base class method.

· Polymorphism In Overriding: To implement late binding in method calling, we use


'virtual' keyword in base class's method and 'override' keyword in derived class's method.
Virtual methods cannot be declared as private because, by definition, they would not be
visible in the derived classes.

· When you have an object of a class, which has a static method, even though you
cannot call the method by object. You still have to call that method by class name
(ClassName.MethodName() not like ObjectName.Method()).

· A static method can access any static member within the class, but it cannot access
an instance member.
· Value Variable In Properties: Even though you do not declare a variable named
'value' in code, but you can still use that variable in properties set segment, because
compiler injects this variable as an argument of a method in IL code, which represents
your set segment of the property.

· Derived class can inherit and override properties just as it could any other member
from the base class. But, if the base class' property contains both get and set segment, you
have to implement both these segment in your derived class version.

· Lazy Initialization: Properties enable a class to guarantee that any additional


processing can be done when a particular field is modified or accessed. This feature of
the properties can be used in the implementation of something called lazy initialization.
This is an optimization technique whereby some of a class's members are not initialized
until they are needed, whose initialization takes up a lot of time or chews up a lot of
resources.

· Arrays

int[] numbers;

numbers = new int[6];

When declaring the array as a member of a class, you need to declare and instantiate the
array in two distinct steps because you can't instantiate an object until run time. (Arrays
are object of System.Array class)

Length() method of an array object return total number of elements that array contains.
Whereas GetLenght() return length or upper bound of the each dimension.

The number of dimensions in an array is called an array's rank, and rank is retrieved
using the Array.Rank property.
A jagged array is simply an array of arrays.

int[][] jaggedArray;

jaggedArray = new int[2][];

jaggedArray[0] = new int[3]

· Indexers: A C#-specific feature called indexers enables you to programmatically


treat objects as though they were arrays.

· Interface: In terms of C++, an interface is basically an abstract class with only pure
virtual methods. All interface methods are public by definition.

· Is Operator: The 'is' operator enables you to check at run time whether one type is
compatible with another type.

if (myControl is ISerializable)

{} else {}

· As Operator: As operator works same as 'is' operator, but in slightly different


manner. It not only checks for compatibility between two types but also try to convert
between. If two types are not compatible with each other, then it assigns a null value to
target type object.

ClsMyClass1 Obj1 = new ClsMyClass1();


ClsMyClass2 Obj2 = new ClsMyClass2();

ClsMyClass2 Obj2 = Obj1 as ClsMyClass2;

If Obj1 and Obj2 were compatible in types then casting would be done, unless Obj2 will
contains a null value.

· When a class implements an interface, by default all the implemented methods are
visible out side the class, because those methods are declared public in the interface. If
you want to hide those methods you have to remove the access modifier 'public' in class
implementation and qualify the members name with interface name.

public interface IDataBound

{void Bind();}

public class EditBox : IDataBound

void IDataBound.Bind()

{}

public static main()

EditBox edit = new EditBox();

edit.Bind(); // This will cause an error.


IDataBound bound = (IDataBound) edit;

Bound.Bind(); // This will run.

This is also used to solve the ambiguity between more then one interfaces, a class is
implementing. For example, a class is implementing more then one interfaces and each is
providing the a method with same name, then you can implement each method by its own
interface qualifier name and at run time you can cast the class object to that particular
interface, who's method you want to call. So, always cast the object to the interface
whose member you're attempting to use.

· Two common problems are associated with interfaces and inheritance:

1) Consider the first problem

1) You have a base class with a method named Foo().

2) You have an interface with a method named Foo().

3) Now you derived a class both from base class and interface, and you do not
implements method Foo() of the interface in that derived class.

4) When you make an object of that derived class and try to call that method Foo(), it
will compile and run without any error (despite the fact that you have to implements all
the methods of an interface in a implementing class). Because when compiler searches
the Foo() method for the interface, it founds that base class method Foo() as implemented
and code works. But it does not give desirable results. And when you cast the derived
class object to the interface type and try to call Foo(), you would probably get the error.

2) Consider the second problem

1) You have an interface with a method Foo().


2) You have a base class which implements that interface and its methods (i.e. Foo())

3) You have a class derived from that base class, and it also have its own method
named Foo() (Declared with 'new' keyword, overriding base class method).

4) Now when you try to call Foo() method by the derived class object, which method will
be called ? It depends on what reference you have. If you have a reference to the derived
class object, its Foo() method will be called. However, when you explicitly cast the
derived class object to the interface, the implemented method of the interface will be
called (base class method).

· You can combine the two or more interfaces in one, so that a class, which is
implementing the combined interface, also implements all the methods of other interfaces
as well.

public interface IA

public interface IB

public interface IX : IA, IB // Combining interfaces

public class MyClass : IX // Implementing all three interfaces

C# Operators:

(), x.y, a[x], ++, --, new, typeof, sizeof (Works on only value types), checked, unchecked,
<operator>= (i.e. +=, -=), >, <, >=, <=, ==, !=,

· Member-By-Member Comparison Of Two Objects:

Object1.Equals(Object2)

It returns true if both object belongs to same class or have same members. When you
compare two objects like (Object1 == Object2) you will get a false value. Because C#
compare objects by their memory addresses and that is different for any two objects.

· When you assign one object to another, basically you are not copying one object to
another. What actually you are doing is that you are making same memory reference for
both of the objects. So that if you make change in one object, it will be reflected in
another one also.

For example:

MyClass Obj1 = new MyClass();


MyClass Obj2 = new MyClass();

Obj1 = Obj2;

Now both objects are pointing the same memory location. And the object Obj1 is
destroyed and eventually collected by GC.

It also happens when you pass the object to a method. When this is the case the object's
reference is actually passes to method, so that any changes (in value of members) in the
passed object in the method code also reflect in the actual object in calling program.

· The continue statement stops the current iteration and returns control back to the top
of the loop for the next iteration.

· If the return statement is a try block that contains an associated finally block,
control is actually passed to the first line of the finally block, and when that block of code
finishes, control is passed back to the caller.

· A Constructor cannot returns value.

· If you put more then one catch block handling different exceptions, you have to put
those block in a order that all the derived exception (from System.Exception) come first,
then at last the type of base class (System.Exception) exception. If not so, then the other
derived exceptions would be unreachable.

· Operator Overloading:
Generic syntax is:

public static retval operator op ( object1 [, object2 ])

All overloaded operator methods must be defined as public and static. The number of
arguments passed (object1, object2) depends on the type of operator being overloaded.

If the operator being overloaded is a binary operator, the first argument must be the same
type as that of the enclosing class and the second argument can be any type.

Only the following unary and binary operators can be overloaded.

Unary operands: +, -, !, ~, ++, --, true, false

Binary operands: +, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, <=

When you overload a binary operator, its compound assignment equivalent is implicitly
overloaded. For example, if you overload the + operator, the += operator is implicitly
overloaded in that the user-defined operator+ method will be called. Also, an operator's
syntax can't be modified. You can't change the binary * operator to take three arguments
when, by definition, its syntax calls for two operands.

· User-Defined Conversions:

Generic syntax is:

public static implicit/explicit operator conv-type-out (conv-type-in operand)

The implicit keyword means that the cast is not required by the client and will occur
automatically. Conversely, using the explicit keyword signifies that the client must
explicitly cast the value to the desired type.

· Delegates:
Callback methods are used when you need to pass a function pointer to another function
that will then call you back (via the passed pointer).

· Events:

Events in C# follow the publish-subscribe design pattern in which a class publishes an


event that it can "raise" and any number of classes can then subscribe to that event. Once
the event is raised, the runtime takes care of notifying each subscriber that the event has
occurred. The method called; as a result of an event being raised is defined by a delegate.
The delegate must be defined as taking two arguments. These arguments always
represent two objects: the object that raised the event (the publisher) and an event
information object. Additionally, this second object must be derived from the .NET
Framework's EventArgs class.

· Threading:

A thread is a unit of processing, and multitasking is the simultaneous execution of


multiple threads. Multitasking comes in two flavors: cooperative and preemptive. In case
of cooperative multitasking, each thread was responsible for relinquishing control to the
processor so that it could process other threads. With preemptive multitasking, the
processor is responsible for giving each thread a certain amount of time in which to
execute — a time-slice. .NET only work on preemptive multitasking operating systems.
In .NET, threads run in something called an AppDomain. In .NET, threads can cross
AppDomain boundaries, and a method in one thread can call a method in another
AppDomain. Therefore, here's a better definition of an AppDomain: a logical process
inside of a physical process.

· Context Switching:

When the hardware timer signals the interrupt, the processor saves all registers for the
current thread onto the stack. Then the processor moves those same registers from the
stack into a data structure called a CONTEXT structure. When the processor wants to
switch back to a previously executing thread, it reverses this procedure and restores the
registers from the CONTEXT structure associated with the thread. This entire procedure
is called context switching.

· You pause or suspend a thread by Thread.Sleep(Milliseconds) static method of the


thread class. You're not allowed to call Thread.Sleep on any other thread except the
currently executing one. The second way to suspend the execution of a thread is by using
the Thread.Suspend method. There is some major difference between the two techniques.
First, the Thread.Suspend method can be called on the currently executing thread or
another thread. Second, once a thread is suspended in this fashion, only another thread
can cause its resumption, with the Thread.Resume method. You can destroy a thread
using it's objects Abort() method. You can set a thread's priority by Thread.Priority
method. The default priority is Normal.

· Through synchronization, you specify critical sections of code that can be entered
by only one thread at a time, thereby guaranteeing that any temporary invalid states of
your object are not seen by the object's clients. We achieve the synchronization between
threads by Monitor class or Mutex Class.

· Reflection:

.NET allows you to write code to access an application's metadata through a process
known as reflection. Reflection is the ability to discover type information at run time. The
reflection API let's you do such things as iterate an assembly's modules, iterate an
assembly's types, and retrieve the different design-time characteristics of a type.
Advanced reflection tasks include using reflection to dynamically invoke methods and
use types (via late binding) and even to create and execute MSIL code at run time. We
have to use following namespaces to works the code:

using System;

using System.Diagnostics;

using System.Reflection;

o Retrieving the type of an instance:

int i = 6;
Type t = i.GetType()

o Retrieving the type from a name:

Type t = Type.GetType("System.Int32");

(Note that you cannot use the C# aliases when calling the Type.GetType method.)

o You can interrogate about a type by first creating a object of that type and then
using its methods, which all start from prefix 'Is' (i.e. type.IsByRef).

o Getting all the types an assembly contains:

Assembly a = Assembly.LoadFrom("MyApp.Exe");

Type[] types = a.GetTypes();

foreach(Type t in types)

{t.FullName;}

o To get all the modules an assembly contains:

Assembly a = Assembly.LoadFrom("MyApp.Exe");

Module[] modules = a.GetModules();


foreach(Module m in modules)

{m.Name;}

o Creating types at run time involves using the System.Reflection.Emit namespace.


Using the classes in this namespace, you can define an assembly in memory, create a
module for an assembly, define new types for a module (including its members), and
even emit the MSIL opcodes for the application's logic.

· Unmanaged code refers to code that is not managed, or controlled, by the .NET
runtime.

· Platform Invocation Services:

o The .NET Platform Invocation Services—sometimes referred to as PInvoke—


allows managed code to work with functions and structures that have been exported from
DLLs.

Attributes are used to provide design-time information for a C# type. Through reflection,
this information can later be queried at run time. C# makes use of an attribute to allow
you to describe the DLL function that the application will call to the compiler. This
attribute is called the DllImport attribute, and its syntax is shown here:

using System.Runtime.InteropServices;

[DllImport("DllName")]

accessModifier static extern retValue dllFunction ( param1, param2,...);

o Not only can a C# application call a DLL function, but the DLL function can also
call designated C# methods in your application. You do it by using function callbac.
o Marshalling: Any time you call a DLL function, .NET has to marshal the
parameters to that function and the return value back to the calling .NET application. It
happens almost implicitly because .NET has a defined default native type for each .NET
type.

o An unmanaged code is a code for which the .NET runtime will not be controlling
the allocation and de-allocation of memory. You write unsafe code by using two
keywords: unsafe and fixed. The unsafe keyword specifies that the marked block will run
in an unmanaged context. The fixed keyword is responsible for the pinning of managed
objects. Pinning is the act of specifying to the garbage collector (GC) that the object in
question cannot be moved. As it happens, during the execution of an application, objects
are allocated and de-allocated and "spaces" in memory open up. Instead of memory
becoming fragmented, the .NET runtime moves the objects around to make the most
efficient use of memory.

o Pointers in C# can be acquired only for value types, arrays, and strings. Pointers
operators in c# are similar to C/C++:

Operator

Description

&

The address-of operator returns a pointer that represents the memory address of the
variable.

The de-reference operator is used to denote the value pointed at by the pointer.

->

The de-referencing and member access operator is used for member access and pointer
de-referencing.
· COM Interoperability:

A .NET application that needs to talk to a COM component cannot directly consume the
functionality that's exposed by that component, because the .NET runtime is designed to
work with components that have metadata, whereas COM is designed to work through
the Registry and a series of interrogatory methods that are implemented by the
component. Therefore, we need to enable a COM component to generate some metadata
for it. In the case of a COM component, this metadata layer is used by the runtime to
determine type information. This type information is then used at run time to manufacture
what's called a runtime callable wrapper (RCW). The RCW handles the actual activation
of the COM object and handles the marshalling requirements when the .NET application
interacts with it. The RCW also does tons of other chores, such as managing object
identity, object lifetimes, and interface caching. The RCW serves the purpose of giving
the .NET application the notion that it's interacting with a managed .NET component, and
it gives the COM component in the unmanaged space the impression that a traditional
COM client is calling it. The TLBIMP utility is used to read and generate metadata of a
COM component. It read the COM type-lib and generates a corresponding metadata
wrapper in the form of a DLL.

One RCW instance is created for each instance of the COM object. The .NET runtime is
concerned only with managing the lifetime of the RCW and garbage collects the RCW.
It's the RCW that takes care of maintaining reference counts on the COM object that it's
mapped to, thereby shielding the .NET runtime from managing the reference counts on
the actual COM object. Any time a COM method raises an error, the COM error is
trapped by the RCW. This error is then converted into an equivalent COMException
class. The .NET client can catch the error with the usual try-catch exception handling
mechanism, and the client has access to the error number, description, the source of the
exception etc.

· We can create an assembly by Assembly Generation tool called al.exe. This tool
takes one or more .Net files or module and generates a single assembly.

· By default, all the .Net assemblies are private. To share an assembly, you must
create a shared name (also known as a strong name) for the assembly by using the Strong
Name tool (sn.exe) that accompanies the .NET SDK. Using this tool first we generates a
key file. That key file contains a globally unique identifier. Then we specify this key file
into one of modules that the assembly is going to contains.

· Using Assembly Cache Viewer (shfusion.dll), we can view detailed information on


a shared assembly.
· Global Assembly Cache tool enables you to perform various tasks on the
assemblies:

Installing an assembly into GAC:

gacutil -i HelloWorld.DLL

Uninstalling as assembly from GAC:

gacutil -u HelloWorld, ver=1,0,0,0

(If you don't specify the version, all the assemblies with the same name would be
uninstalled.)

· Assembly's version number comes in the format:


(<major><minor><build><revision>). Versioning pertains only to share assemblies—
private assemblies need not apply.

Quick Fix Engineering updates, or hot fixes typically doesn't modify the code's interface,
the chances that client code will be adversely affected are minimal. Therefore, the default
versioning policy is to automatically associate all client code to the new "fixed" version
of the code unless a configuration file exists for the application that explicitly associates
the application with a specific version of an assembly. A new version of an assembly is
considered to be a QFE if the only part of the version number that changed is the revision
part.

Você também pode gostar