C # for delphi wevelOpers1.0 022202
Foreword
This document is intended to be a reference for those Delphi programmers who want to learn C #. It explains how to translate your existing knowledge to C #. I hope you could forgive my mistakes, I'm not an english speaker and you are invited to send ME Any Bugs or Incorrect Information You Find At Studio@qadram.com, I will fix it as soon as possible.
Introduction
C # IS a Component-Oriented Language, In The Same Way Delphi and C Builder Are, But It Goes a bit beyond this concept. This is not a c # manual, after the means manual, you must buy some c # book to Learn All The New Features C # Have and Delphi Not. Some Descriptions and Difference Are Explained "Roughly", IS Just An Introduction To C # for delphi development, it's not an in-depth C # manual.
Some Things this Manual Doesn't Cover
How to compile or execute C # programs Attributes Interfaces Nested Classes Versioning C # language syntax Conversions Arrays Indexers Enumerators User-defined Conversions Operator Overloading COM .NET Framework XML
Is this Manual for you?
If you are a Delphi developer who wants to know how to translate your knowledge to C #, this is the first document you might want to read. It introduces you in the C # by explaining how to do the things you already do with Delphi. This manual Is Only About The Language C #, NOT The .NET Platform Nor The Visual Studio .NET IDE, NOR Components.
About the Author
José León Currently Works As Web Developer for a Company In Spain, IF You Want To Know More About Him, Just Go To http://www.qadram.com
QuickStart
Look at this Source Code:
Using system;
Class Hello
{
Public static void main (string [] args)
{
Console.writeline ("Hello, From C #"); for (int Arg = 0; arg
{
Console.WriteLine ("arg {0}: {1}", arg, args [arg]);
}
}
}
When the Program Loads, The Main Function IS
Executed, IT Writes A String to the console and
Iterates through the parameters to dump the
Number of Parameters and ITS Value.
Main Differences:
Using INSTEAD OF USES
To Add External FunctionAllity
There's no code outside a class,
There Are no global functions in c #
The IMplementation of a Method IS
Tied to ITS Declaration
DataTypes
The Following Table Shows The Correlation
Between Delphi Data Types and C # data
Types:
Delphic # bytebeteshortintsbytesmallintshortwordushortintegerintShortWordushortintegerintShibardinal, LongwordUintint64longulongsinglefloatDoubledoublecurrencyDecimalstringstringCharCharBooleanBool
The Main Diference Between Delphi
DataTypes and C # DataTypes IS Not ITS Name, in
C #, Datatypes Are Derived from the base class
Object, So it's Possible to WRITE
Sentences like this:
Console.writeline ("Value IS: {0}", 3.Tostring ());
Which is not Possible in Delphi, this
Technique Is Called Boxing.
Exception Handling
I can't See Many Differences Between C #
Exception Handling and Delphi's One, IT'S
Another Syntax But Nothing Moreing Moreing More:
Try .. except .. End
Try
{
INT J = 22 / ZERO;
}
Catch (Exception E)
{
Console.writeline ("exception" E.MESSAGE);
}
If you want to catch diffreent Kind of
Exceptions You Just Only Need to Write Several
Catch Blocks. The Ancestor Of All
Exceptions is the Exception Class, The EXCEPTION
Same as delphi.
Try
{
INT J = 22 / ZERO;
}
Catch (DivideByzeroExcection E)
{
Console.writeline ("exception" E.MESSAGE);
}
Catch (Exception E)
{
Console.writeline ("exception" E.MESSAGE);
}
The catch block what catches the cardyzeroexception is the more specific
Match.
Try..finally..nd
C # also supports try..finally
Using Similar Syntax To Delphi
FILESTREAM F = New FileStream ("DATA.TXT", FileMode.Open;
Try
{
// Perform Operations with the file
}
Finally
{
f.close ();
}
There's Another Option Which is equivalent to
This delphi code:
Try
Try
Except
// manage here your exceptions
end
Finally
// Perform Some Cleanup Here
END;
IN C # you can write:
Try
{
}
Catch (Exception E)
{
Console.writeline ("exception" E.MESSAGE);
}
Finally
{
// Perform Some Cleanup Here
}
In Delphi, You Should Destroy Any Object
You create or free any resource you allocate.
The primary use of exception handling is to
EnSure Everything is destroyed and freed.
Because C # HAS Garbage Collection, you don't
NEED TO WORRY About this, you will use
Exception Handling Only To Ensure The Proper
Finalization of Operations, SO this Improves
The efficiency of the code.
Classes
C # classes work like delphi, you don't
Need to Learn New Oo Concepts, The Main
Difference, At Source Code Level, Is The Code
Is Written Just Below The Prototype of A
Function.
Class myclass
{
Public int myfunction ()
{
Return (5);
}
}
Also You Must Specify THE VISIBILITY OF
Each Member of a Class (Field, Method, ETC),
Because They isy default. for
EXAMPLE:
Class Myinteger
{
INT INTEGER = 0;
}
If you create an instance of
Myinteger and you use the integer field
Of the myinteger class, this will
Product an error Because IS
Private:
Class testprivate
{
Public static void main ()
{
Myinteger mi = new myinteger ();
Console.writeLine ("{0}", mi.integer;
}
}
This Will Produce An Error, You Mustspecify Public When Decilaning a Member
Visible to other classes.
In the previous case, you don't need
Destroy the Mi Variable, The Garbage
Collector Does It for you. in Delphi you can
Use self inside a class to reason to the
Current Instance, In C # use this instead
Self.
Constructors
Constructors are not labeled with the
Constructor Reserved Word, In C #, Constructors
Are Me MEMBER FUNCTIONS with The Same Name of The
Class:
Class Point
{
Public Point (int x, int y)
{
THIS.X = X;
THIS.Y = Y;
}
Public int x;
Public int y;
}
Ref and out parameters
To Get Several Values at ONCE FROM A
Function, in Delphi you use var, to
INDICATE A Reference Parameter, The Function
Can Modify The Parameter and The Caller Will
Know the New value.
There area Two Ways to do this in c #, you
CAN use ref or out. the
Difference is The Compiler Won't allow to pass
Uninitialized Variables as REF
Parameters.
Class Point
{
Public Point (int x, int y)
{
THIS.X = X;
THIS.Y = Y;
}
Public void getPoint (Ref Int X, Ref Int Y)
{
x = this.x;
Y = this.y;
}
INT X;
Int Y;
}
To call the getpoint member of the point
Class, You Should Call IT AS:
INT x = 0;
INT Y = 0;
Apoint.getPoint (Ref x, ref y);
IF you forget to initialize the
Parameters, The Compiler Will Generate An
Error, IF you don't want this, just change
Ref by out.
OVERLOADING
To Declare Several Methods in a class
With The Same Name and Different Parameter
List, you don't need to mark the as
Overload. The Compiler Chooses Which To
Call by matching the parameters in the call trum
The parameters declared for the
Function.
Inheritance
To create Derived Classes from Base
Classes, you can do it this way:
Class Baseclass
{
Public BaseClass ()
{
// do something
}
}
Class DerivedClass: Baseclass
{
Public derivedclass ()
{
}
}
One Big Difference IS Constructors Cannot
Be inherited, so you must ask, how can I call
The base class constructor ?. in Delphi, you can
Use the inherited reserved word, in c #
You Use the base syntax. Look at The Base SYNTAX.
FOLLOWING SAMPLE:
Class Baseclass
{
Public BaseClass (String Param, Int Value)
{
This.Param = param;
THIS.VALUE = VALUE;
}
String param;
Int value;
}
Class DerivedClass: Baseclass
{
Public DerivedClass (String Param, Int Value): Base (param, value)
{
}
}
Using the base syntax, you call
The constructor from the base class with the bas
Parameters of the constructor of the derived
Class, if You Omit The Base Syntax, The Base Syntax, The Base
Base Class Constructor Will Be Called With No
Parameters.
Virtual functions
To Declare Virtual Functions and Override
THEM IN DERIVED CLASSES, THE SYNTAX IS VERY
Similar to delphi, To ALLOW A FUNCTION BE
Overritten in a Derived Class, You Must Declare
IT As Virtual, And in a Derived Class To
Override a Function from the base class, you
Must Declare it as override.
Class Baseclass
{
Public BaseClass (String Param, Int Value)
{
This.Param = param;
THIS.VALUE = VALUE;
}
Virtual public getValue ()
{
Return (Value);
}
String param;
Int value;
}
Class DerivedClass: Baseclass
{
Public DerivedClass (String Param, Int Value): Base (param, value)
{
}
OVERRIDE PUBLIC GETVALUE ()
{
Return (Value * 5);
}
}
Abstract Classes
If you want to force a derived class to
Override One or more Members, You Can Declare
THEM As Abstract, this means you don't
NEED TO CREATE AN IMPLEMENTATION for Thatmember in the base class and you are forcing a
Derived Class to Implement IT.
There Are Several Differences Between C #
And Delphi, in Delphi, you can declare an
Abstract MEMBER, But you are not forced
To Implement It On a Derived Class, You Will
Get Just A Warning, And in Runtime, IF you call
This Member, You Will Get An Abstract
Error.
IN C # you are forced to import AN
Abstract MEMBER IN A Derived Class, IF
You don't do it, The program won't compile.
Also, if you declare an abstract member
ON a class, you must declare the class as
Abstract and you can't create installation
Of That Class Because IT Contains Missing
FunctionAlity. Look at this Example:
Abstract Class Baseclass
{
Public BaseClass (String Param, Int Value)
{
This.Param = param;
THIS.VALUE = VALUE;
}
Abstract public getValue ();
String param;
Int value;
}
Class DerivedClass: Baseclass
{
Public DerivedClass (String Param, Int Value): Base (param, value)
{
}
OVERRIDE PUBLIC GETVALUE ()
{
Return (Value * 5);
}
}
You cannot Create Instances of Baseclass,
And if you don't override the member getValue,
The Program Won't compile.
Sealed Classes
There's Another Feature I Think Delphi
Doesn't Have, IS Called Sealed Classes, and IS
A Way to Prevent DeriVation from a base
Class.
This Program Will ProductAN
Error:
Sealed Class Myclass
{
Myclass ()
{
}
}
Class Derived: Myclass
{
}
Class Member Accesibility
In Delphi, You Can Declare Several
Classes in The Same Unit, Let's Suppose Class A
And Class B, if you declare a private member on
Class A, You CAN Access That Member INSIDE
Class B.
Tclassa = Class
Private
A: Integer;
END;
Tclassb = Classpublic
Procedure hello;
END;
IMPLEMENTATION
Procedure tclassb.hello;
VAR
Classa: tclassa;
Begin
Classa: = tclassa.create;
Classa.a: = 5;
END;
In C # this is not the default behaviour,
To Achieve this Behaviour, You Must Declare T
MEMBER AS INTERNAL.
Public Class Classa
{
INTERNAL INT A;
}
Public Class Classb
{
Public void Hello ()
{
Classa ca = new classa ();
Ca.a = 5;
}
}
In c # there is a concept called
Assembly, Which Can Be Considered Asia
Package for delphi development. Declaring
INTERNAL A MEMBER OF A Class, You CAN
Access That Member from any class inside the
Same assembly, but not from a class outside the
Assembly.
The Internal Syntax Can Also Be
Used with classes, Because if you don't specify
a Visibility for a class (i.e. public), The
Class Could NOTBE. Outside The assembly.
TO CREATE A Class That Could Be Used "Only"
INSIDE The assembly, Declare IT AS
Internal.
Destuction
There Are Important Differences Between
Delphi's Memory Management and C # 's One. In
Delphi you sell take care to destroy Each and
Every Object You Create To Avoid Memory Leaks,
But in c # you don't have to worry about
That.
Strictly speaking, c # doesn't has
Destructors, At Least Not in The Way Delphi
Does. in c # a destructor is like a finalizer
And is caled by the garbage collector when the garbage
Object is collected. so the destructor is not
SO USeful As in Delphi, We Must Provide Another
Method for the user of out j ject to perform
Cleanup.
Static Fields and Member Functions
In Delphi, THE Easiest Way (and the only
Way I know) to have a field shared by several
Instances of the Same Class, IS Declare IT
Outside the class. declare it as a globalvariable or a local variable under the
Implementation section. But C # Gives US Another
Way to do it, you can Declare a member of a
Class as static, this means, it's value
Will Be Shared Among All The Instances of The INSTANCES OF
Same Class, And It's Accessed THROUGH THE NAME
Of the class, instead the name of the
INSTANCE.
Class StaticClass
{
Public staticclass ()
{
INSTANCES ;
}
PUBLIC Static Int Instances = 0;
}
Class Statictest
{
Public static void main ()
{
StaticClass sc = new staticclass ();
Console.writeline (staticclass.instances);
StaticClass sc2 = new staticclass ();
Console.writeline (staticclass.instances);
}
}
Also, You Can Declare Methods of The
Class as static, and in That Case, Works
In The Same Way AS Class Methods in
Delphi.
Constants
To Declare a constant, you just need
Declare it with the const modifier and
Assign IT a Value, But you must include the
TYPE OF THE VALUE.
Public const Int value = 33;
But there is another powerful feature to
Allow US Initialize Constants to a Value WE
Don't Know At Compile Time. this Feature IS
Called readonly. if we use
Readonly modifier instead the
Const modifier when declaring a
Constant, We are allowed to set its value. ONLY
At the constructor of a class. if we try to ration. IF WE TRY TO
Modify it in another location, we will get an
Error.
Class ReadonlyClass
{
Public ReadonlyClass (Int Value)
{
THIS.VALUE = VALUE;
}
Public Readonly Int Value;
}
In this Way, Value Could Not Be
Modified in Any Part of The Program Except in
ITS Constructor. Works Very Similar To Readonly
Properties, But in My Opinion, THE SYNTAX IS
Much more clear.
Variable parameters
In Delphi, A Function Can Take a Variablenumber of Parameters, C # is Able To Do this in
A fancier warbause in c # Everything is an
Object, Take a Look At this code:
Class VariableParameters
{
Public void write (string line, params object [] args)
{
For (int index = 0; index { Console.writeline (args [index] .tostring ()); } } } Class testvariableparameters { Public static void main () { VariableParameters vp = new variableparameters (); Vp.write ("Hello", "World!"); vp.write ("params:", "a", "b", 12, 15); Object [] arr = new object [4]; Arr [0] = "these"; Arr [1] = "all"; Arr [2] = 4; Arr [3] = "Params"; vp.write ("params:", arr); } } IF we use the params keyword on a Parameter of a function, we are able to pass as Many Parameters as we want to That function. The Compiler INTERLY Converts That List of Parameters to an Array and Calls the function With That Array, The Same as in The Third Call. Structs STRUCTS Are Really Different To Dephi Records, Because They Inherit from Object, ACT Like Objects But With A Few Restrictions, They Can't inherit from any other type and other Classes can't inherit from them. It's really Strange to See a struct that has methods, but WE Must Think That Is An Object, in The Same Way an integer or a string. SO We can write this code: Struct Rect { Public RECT (INT X1, INT Y1, INT X2, INT Y2) { THIS.X1 = x1; THIS.Y1 = Y1; THIS.X2 = x2; THIS.Y2 = Y2; } Public override string toString () { Return (String.Format) - ({0}, {1}) - ({2}, {3}) ", X1, Y1, X2, Y2); } Public INT X1; Public int y1; Public int x2; Public int y2; } Class TestRect { Public static void main () { Rect Bounds = New RECT (100, 100, 200, 200); Console.WriteLine ("Bounds: {0}", Bounds; } } This Code Is So Strange to a Delphi Developer, Because First, DECLARES METHODS IN A Struct, Second, A Method Uses the override Reserved Word, And Third, The Struct Is Written To the console. WE CAN DECLARE METHODS IN A STRUCT Because is an Object, Because is an Object WE Can Override Certain Functions of the Object Ancestor (Tostring Is Available for All Objects, and the toString method is called for Each An Every Object Is Passed to The WriteLine Function. Sentences I'm not going to write here all the Sentences of delphi and its Equivalent in C # BECAUSE MOST Part Are the Same In C , you SHOULD Read Another Tutorials / Books About That. Switch Switch is equivalent to copy in Delphi, But Has A Total DiffERENT SYNTAX: Switch (condition) { Case 1: Case 2: // Do Something Here for Case 1 and case 2 Break; Case 3: // Do Something Here for Case 3 Break; DEFAULT: // Handle Here The Default Case } Works Very Similar To C But It Requires A Break at the end of each case block, this is A Common Mistake In C , So The Compiler Gives An Error if there's no Break. Foreach C # incorporates a feature to make Items Simpler, IS Called Foreach, And Allows to Itereate Easily Through AN Array (Also Allows Another Types, But It's Outside of the Scope of this manual). LOOK this Code: Public Static void foreachtest (arraylist myarray) { For (int i = 0; i { MyObject Current = (MyObject) MyArray [i]; Console.WriteLine ("item: {0}", current); } } With foreach, you can write the prep As Follows: Public static void foreachtest (arraylist myarray) { Foreach (MyObject Current in MyArray) { Console.WriteLine ("item: {0}", current); } } Return Return, Returns to the Calling Function And Optionally Returns a Value, IS LIKE ASSIGN A Value to Result and make an exit. AS and IS Thase Operators Can Be Used in the Same Way in Delphi, You Can Know The Type of An Object / Interface and Force It to be of A Specified Type. Strings Because strings are Objects Too, you can Apply to string Variables Several Methods to SEVERAL METHODS TO Compare Them, Make Operations, Iterate, ETC. This is a brief List of all the methods That Supports a string: Compare () Compareordinal () compareto () endswith () StartSwith () indexof () LastIndexof () CONPYTO () INSERT () JOIN () PADLEFT () Padright () remove () rff () Padright () remove () Replace () split () subside () Replace () split () Substrng () TOLOWER () TouPper () Trim () Trimend () Trimstart () To make String Processing Easier, There's a class caled stringbuilder which can be Useful to make such operations. Regular Expressions To Deal with regular expressions, there. a class called regex which handles all this Stuff. You Just Create a New Object of Regex Class and as parameter you use the regular Expresion, Then You Can Use the Several Methods Provided with this class to perform operations TO STRINGS. PROPERTIES The Syntax for Properties Is Totally Different to del Phi's One. in Fact, IF you Don't pay attention, you can't see a Property, Because IT Looks Like A Method. The Concept Is The Same, A Property IS A Way to get the value from a field of an object, Or to set That Value, A Property Itself it's NOT A Value. Look That Code: Class test { PRIVATE STRING NAME; Public String Name { get { Return Name; } set { Name = value; } } Personally, i prefer the way delphi Declares Properties, for Example, you see the Value Parameter of the Set Accessor, But Here Is Hidden. IF a property HAS Only A Get Accessor (Getter), IT's A Read-Only Property, And iF IT HAS Only A Set Accessor (SETTER) IT'S A Write-only property. Delegates In Delphi You CAN WRITE: Type Twakeupevent = Procedure (Sender: TOBJECT; WHEN: integer) OF Object; You are Creating a Procedural Type, THEN You can Declare Variables of That Type, And This Mechanism Is Needed When Decilang Events. IN C #, The Concept is Called Delegate, in C #, The Previous Line Can Be Written As Follows: Public Delegate Void Twakeupevent (Object Sender, Int when); Because in C #, All The Code Must Be Written Inside a class, you don't need Specify of Object. after this decaration you Can Write: Class Wakeme { Public Delegate Void Twakeupevent (Object Sender, Int when); Public void Wakemeup (Twakeupevent Wakemeup) { WakeMeup (Anobject, 500); } } But this Has Some Drawbacks, Because you Must Create An Instance of The Delegate, Passing as an argument, the function you want To be caled. Class test { Public Static Void Notified (Object Sender, INT WHEN) { Console.writeline ("When: {0}", when); } Public static void main () { Wakeme WM = New Wakeme (); Wakeme.twakeupevent ev = new wakeme.twakeupevent (notified); Wakeme.wakemeup (EV); } } Events Events in c # area based in delegates, and There's a design conveterion to design THE Delegates to take always two parameters, the First Is The Object That Fired The Event and The Second Parameter Is An Object That Contains The Information About The Event, this Object IS Always Derived from Eventargs. Indelphi, The Convenction Is To Define An Event With sender as first parameter and the REST OF INFORMATION IN SEPARATE Parameters. Class MyEventArgs: Eventargs { Public myEventArgs (String Name, String Value) { THIS.NAME = Name; THIS.VALUE = VALUE; } Public String Name { get { Return (Name); } } Public String Value { get { Return (Value); } } String name; String value; } Class MyNotify { Public Delegate Void MyEventHandler (Object Sender, MyEventArgs E); Public Event MyEventhandler OnMyeventHandler; Protected Void Onmyevent (MyEventargs E) { IF (OnMyeventHandler! = NULL) OnMyeventHandler (this, e); } Public void NotifyEvent (String Name, String Value) { MyEventargs E = New MyEventArgs (Name, Value); OnMyEvent (E); } } Class mywatcher { Public myWatcher (MyNotify MyNotify) { THIS.MYNOTIFY = MyNotify; MyNotify.onMyevent = new mynotify.myeventhandler (myFunction); } Void MyFunction (Object Sender, MyEventArgs E) { Console.writeline ("new mail: {0} {1} ", E.NAME, E.VALUE } MYNOTIFY MYNOTIFY; } Class test { Public static void main () { MyNotify MyNotify = new mynotify (); MyWatcher MyWatcher = new mywatcher (mynotify); MyNotify.NotifyEvent ("this is a name", "this is a value"); } } The First Time I Saw this Code, I Started To Think That C # is Not as Good with Events AS Delphi, But Let's Look at the line: MyNotify.onMyevent = new mynotify.myeventhandler (myFunction); THIS LINE Assigns a Handler To The Event, But then, why =, INSTEAD A Simple Assignment? In C #, INSTEAD Assign a Pointer to an Event, You are "subscribing" to a notification list, That Means, Several Functions Can Be Notified When An Event Is Fired without do anythingspecial. this feature is really useful. in C #, This Feature IS Called Multicast, And there is TWO Things you must be aware, The Order in Which Delegates Are Called is not defined, and if one Delegate throws an exception, Maybe, The Other Delegates Are Not Called. Conclusion IF you get a c developer who change to Delphi Due Rad Capabilities (this is my story ;-)), you will feel Very Comfortable with C #, IT GIVES you the best of c with a delphi Flavour.