수안이의 컴퓨터 연구실

  • Mainpage
  • About Me
  • Tags
  • Metapage
  • Notice
  • Location
  • Keywords
  • Guestbook
  • Admin
  • Write an Article
  • Total | 1691128
  • Today | 434
  • Yesterday | 628

11 Articles, Search for 'C#'

  1. 2008/02/02 Cheat Sheet의 모든 것
  2. 2007/07/27 Introduction to Objects and Classes in C#
  3. 2007/07/27 Socket Programming in C#
  4. 2007/07/27 Creational Patterns in C#
  5. 2007/07/27 Exception Handling in C#
  6. 2007/07/27 Network Programming in C#
  7. 2007/07/26 IOCP Thread Pooling in C#
  8. 2007/07/02 C# 키워드 목록
  9. 2007/06/26 Event Handling in .NET Using C#
  10. 2007/05/03 C# 명령줄 컴파일러 옵션
Programming2008/02/02 21:33

Cheat Sheet의 모든 것

Actionscript
  • Quick reference/Cheatsheet for ActionScript 2.0
  • ActionScript 3.0 Cheatsheet - flash.display Package
  • ActionScript3.0 - Top Level Classes
  • ActionScript3.0 - Packages
  • Apollo Cheat Sheet (Apollo mx.controls & mx.core Cheatsheet, Apollo flash.display & flash.events Cheatsheet and Apollo flash.filesystem, flash.html & flash.system Cheatsheet)

Ajax

  • What’s Ajax? Cheat Sheet - PDF
  • Prototype Dissected - Cheat Sheet PNG
  • scriptaculous Combination Effects - Cheat Sheet - PDF

Apache

  • Apache Cheat Sheet
  • Apache 1.3 Quick Reference Card - free quick reference cards - PDF
  • htaccess Cheatsheet
  • mod_rewrite Cheat Sheet - PNG
  • mod_rewrite Cheat Sheet - PDF

ASCII Character Codes

  • ASCII Codes Cheat Sheet
  • Character Entity References in HTML 4 and XHTML 1.0
  • HTML Character Entities Cheat Sheet - PNG
  • HTML Character Entities Cheat Sheet - PDF
  • HTML special character reference
  • HTML - Special Entity Codes
  • Reference Special Characters
  • Special ASCII HTML Character Codes
  • XHTML Character Entity Reference

ASP

  • ASP / VBScript Cheat Sheet - PNG

C# and VB.NET

  • C# and VB.NET Comparison Cheat Sheet - PDF
  • Cheat Sheet - Casting in VB.NET and C#

CSS

  • CSS level 1 - Quick Reference Card - PDF
  • CSS level 2 - Quick Reference Card - PDF
  • CSS 2 - Quick Reference Guide - PDF
  • CSS Cheat Sheet - PDF
  • CSS Cheat Sheet - PNG
  • CSS Property Index
  • Cascading Style Cheatsheet
  • CSS Shorthand Guide

CVS

  • CVS Cheat Sheet
  • Subversion Quick Reference Card - PDF
  • CVS Cheat-sheet

C++

  • C++ Containers Cheat Sheet
  • C++ Quick Reference Sheet (Cheat Sheet) - PDF
  • How to Program in C++ - Language Summary

Django

  • Django Cheat Sheet
  • The Django Book

Firefox

  • Firefox Keyboard Shortcuts - PDF
  • Firefox Shortcuts Sheet
  • Mozilla Firefox Cheat Sheet
  • Mozilla Thunderbird Cheat Sheet
  • Keyboard Shortcuts

Google

  • Gmail Shortcuts (printable cheatsheet)
  • Google Advanced Operators (Cheat Sheet)
  • Google Cheat Sheet (Version 1.06) - PDF
  • Google Cheat Sheet - auch als PDF
  • Google Cheat Sheets - auch als PDF
  • Google Help : Cheat Sheet

HTML/XHTML

  • A Simple Guide To HTML - Cheat Sheet
  • HTML & XHTML Tag Quick Reference
  • HTML Cheat Sheet
  • HTML Cheatsheet
  • HTML Entities
  • HTML CODES CHEAT SHEET
  • XHTML
  • HTML Cheat Sheet
  • XHTML Cheat Sheet v. 1.03 - PDF
  • HTML DOM - Quick Reference Card - PDF
  • XHTML 1.0 frameset - Quick Reference Card - PDF
  • XHTML 1.0 strict - Quick Reference Card - PDF
  • XHTML 1.0 transitional - Quick Reference Card - PDF
  • XHTML Quick Reference Guide For XHTML 1.1

Java

  • Java 1.5 Cheat Sheet
  • Java Quick Reference - PDF
  • JSP Quick Reference Card
  • (JSPª) SYNTAX version 1.1
  • (JSP™) SYNTAX version 2.0

JavaScript

  • JavaScript Cheat Sheet - PNG
  • JavaScript Cheat Sheet - PDF
  • JavaScript Reference
  • JavaScript Reference
  • JavaScript and Browser Objects Quick Reference
  • Regular Expressions for JavaSript - free online quick reference

LaTeX

  • Latex cheat sheet
  • LATEX2″ Cheat Sheet
  • Latex 2e Cheat Sheet LaTeX 2e Brief Reference

Microformats

  • Microformats Cheat Sheet
  • Microformats Cheat Sheet

Misc

  • CHMOD Chart
  • Complete listing of common camera symbols.
  • The Unicode-Database
  • RGB Hex Colour Chart - PNG
  • Pretty Good PGP Reference Card
  • Search Engine Cheat Sheet
  • Quick Reference Cards
    Ada, C, C++, CSS, CVS, Delphi, DOC++, Html, Java, JSP, Perl, PHP, Linux, Unix, SQL, UML, XML

MySQL

  • MySQL Cheat Sheet
  • MySQL Cheat Sheet - PDF
  • MySQL Cheat Sheet - PNG
  • MySQL Cheat Sheet
  • SQL Cheatsheet
  • MySQL Quick Reference Card

Oracle

  • Oracle PL/SQL Cheatsheet
  • Oracle Cheat Sheet
  • Oracle Server 9i - Quick Reference Guide
  • Oracle SCM Installation Cheat Sheet

Perl

  • Perl Regular Expression -Quick Reference - PDF
  • Perl Cheat Sheet
  • Perl Cheat Sheet
  • Perl 5 Cheat Sheet
  • Perl Quick Reference - PDF
  • Perl Quick Reference Card - PDF
  • Perl Regexp Quick Reference Card - PDF

Photoshop/Gimp

  • Gimp Quick Reference Card v.1.0
  • Photoshop 7.0 Quick Reference Card for Windows - PDF
  • Photoshop CS2 Keyboard Shortcuts (Windows) - PDF
  • Photoshop CS2 Keyboard Shortcuts (Macintosh) - PDF

PHP

  • symfony PHP5 framework - Admin Generator cheat sheet - PDF
  • PHP Cheat Sheet - PDF
  • PHP Cheat Sheet - PNG
  • PHP Cheat Sheet with special php syntax
  • PHP PCRE Cheat Sheet
  • Regular Expressions Cheat Sheet - PNG
  • Smarty cheat sheet for template designers - PDF

Python

  • Python 101 cheat sheet
  • Python Cheat Sheet
  • Python Cheat Sheet - PDF
  • Python Quick Reference
  • Python 2.4 Quick Reference

Regular Expressions

  • Regular Expressions Cheat Sheet
  • Regular Expression Cheat Sheet (.NET)

Ruby

  • ActiveRecord Relationships - Ruby on Rails cheat sheet guide - PDF
  • Ruby Cheatsheet
  • RubyOnRails-Cheatsheet - PDF
  • Ruby on Rails Cheat Sheet - PNG
  • Ruby on Rails Cheat Sheet Collectors Edition
  • Ruby on Rails cheat sheet guide - PDF
  • Ruby quick reference
  • Ruby Cheatsheet
  • Threadeds Ruby Cheat Sheet
  • What Goes Where? - Ruby on Rails cheat sheet - PDF

Unix/Linux

  • LINUX Administrator’s Quick Reference Card - PDF
  • Linux Shortcuts and Commands
  • quick_reference [GNU screen]
  • Unix Cheat Sheet
  • The One Page Linux Manual - Version 3 - PDF
  • TCP Ports list (3498 ports in list)
  • Treebeard’s Unix Cheat Sheet
  • Unix command cheat sheet - common commands for the unix command line
  • Essential Vim keyboard shortcuts Cheat Sheet
  • VIM Quick Reference Card
  • VIM Quick Reference Card
  • Vim Commands Cheat Sheet

Weblog

  • Blogger Cheatsheet - PDF
  • Quick Reference Chart - ExpressionEngine Documentation - PDF
  • TypePad Cheatsheet - PDF
  • Movable Type Cheatsheet - PDF
  • MovableType
  • WordPress Cheatsheet - PDF
  • WP - WordPress Cheat Sheet für Theme Tags und Plugin-API - PDF

Windows

  • An A-Z Index of the Windows NT/XP command line
  • Graphical vi-vim Cheat Sheet and Tutorial
  • Power Point 2000 - Keyboard Shortcuts
  • POWERPOINT 2003 - Quick Reference Card
  • Quick Reference Card for Windows®
  • TCP Ports list (3498 ports in list)
  • Windows - Alt Key Numeric Codes
  • Windows XP Service Reference - PDF
  • XP Keyboard Shortcuts: version 2 - PDF

XML

  • Fusebox 4.1 XML Cheat Sheet
  • MathML Reference - PDF
  • VoiceXML Reference - PDF
  • XML TopicMaps 1.0 - Quick Reference Card - PDF
  • XML Quick References - PDF
  • XML Schema 2001: children - parents - PDF
  • XML Schema 2001: elements - attributes - PDF
  • XML Schema 2000/10 - PDF
  • XML Schema - Structures Quick Reference - PDF
  • XML Schema - Data Types Quick Reference - PDF
  • XSL FO Reference - PDF
  • XSLT Quick References - PDF
  • XSLT Quick Reference Card - PDF
  • XSLT Reference

출처 : http://www.smashingmagazine.com/2006/10 ··· -ruby%2F

"Programming" 카테고리의 다른 글
  • Top 119 Cheat Sheets (0)2008/05/03
  • Cheat Sheet의 모든 것 (0)2008/02/02
  • Visual Studio 2005 Shortcut Keys (0)2007/08/17
  • WinDbg 간단 사용법 (0)2007/08/16
  • WinDbg 사용법 (0)2007/08/16
2008/02/02 21:33 2008/02/02 21:33
Posted by webdizen
Tags ActionScript, Ajax, Apache, ASCII Character, ASPKeyword ASP, C#, C++Keyword C++, CSS, CVS, Django, Firefox, Gimp, Google, HTML, Java, Javascript, LaTeX, Linux, Microformats, Misc, MySQL, Oracle, Perl, Photoshop, PHP, Python, Regular Expressions, Ruby, Unix, VB.NET, Weblog, Windows, XHTML, XML
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3175

Leave your greetings.

[로그인][오픈아이디란?]

Programming/C#2007/07/27 09:27

Introduction to Objects and Classes in C#

출처 : http://www.devarticles.com/c/a/c-sharp/ ··· sharp%2F

Introduction to Objects and Classes in C#
(Page 1 of 9 )

In this article Michael introduces us to C#, as well as attempts to demystify the theory behind "Object and Classes" in OO Programming.

In this article I will explain some of the concepts behind object-oriented programming in C#, including objects and classes. To read this article you should have some basic understanding of the C-Sharp language.

Read the whole article because there are some concepts you may not fully understand until you finish the article. And we will revisit all the concepts more than once when I see it's appropriate in future articles; so don't worry at all.

Introduction to Objects and Classes in C# - Introduction
(Page 2 of 9 )

OOP stands for Object-Oriented Programming. OOP is relatively a new way to program computer applications. In the past, OOP programmers used to create computer applications using procedural-programming (or structured-programming). But, when OOP solved a lot of the problems of the procedural-programming, most programmers and developers began using OOP languages. In procedural- programming all the program functionality is written in a few modules of code or maybe one module (depending on the program). These modules depend on one another and sometimes changing a line of code requires you to rewrite the whole module again and maybe the whole program. 

In Object-Oriented Programming programmers write independent parts of a program called classes. Each class represents a part of the program functionality and these classes can be assembled to form a program. When you need to change some of the program functionality all you have to do is to replace the target class which may contain the problem that needs change. So, OOP applications are created by the use of classes and these applications can contain any number of classes. This will get us to discuss the Class and Object concept.


Classes and objects

You may find it a little difficult to understand the class and object story; but, I will try to do my best in explaining it. Actually the class and object concept is related to each other. Some beginners don't care about understanding it clearly so I think they will have a hard time learning C#.

Object-Oriented concepts take most of their functionality from the real-life concepts. For example, I will discuss the concept of Classes and Objects of the world first and then you will understand the computer's Classes and Objects before I even write anything about it.

Introduction to Objects and Classes in C# - World's Classes and Objects
(Page 3 of 9 )

In our world we have classes and objects for those classes. Everything in our world is considered to be an object. For example, people are objects, animals are objects too, minerals are objects; everything in the world is an object. Easy, right? But what about classes?

In our world we have to differentiate between objects that we are living with. So we must understand that there are classifications (this is how they get the name and the concepts of the Class) for all of those objects. For example, I'm an object, David is object too, Maria is another object. So we are from a people class (or type). I have a dog called Ricky so it's an object. My friend's dog, Doby, is also an object so they are from a Dogs class (or type).

A third example: I have a Pentium 3; this is an object.  My friend has a Pentium 4, so this is another object and they are from a Computers class (or type). Now I think you understand the concept of the Class and Object, but let me crystallize it for you. In our world we have classifications for objects and every object must be from some classification. So, a Class is a way for describing some properties and functionalities or behaviors of a group of objects. In other words, the class is considered to be a template for some objects. So maybe I will create a class called person which is a template of the functionality and the properties of persons.

Introduction to Objects and Classes in C# - Programmer’s Classes and Objects
(Page 4 of 9 )

A C# Class is considered to be the primary building block of the language. What I mean by the primary building block is that every time you work with C# you will create classes to form a program. We use classes as a template to put the properties and functionalities or behaviors in one building block for a group of objects and after that we use the template to create the objects we need.

For example, we need to have persons objects in our program so the first thing to do here is to create a class called Person that contains all the functionalities or behaviors and properties of any person and after that we will use that class (or template) to create as many objects as we need. Creating an object of a specific class type is called "an instance of the class". Don't worry if you didn't grasp it 100% and don't worry if you don't know what the class and object's properties and functionalities or behaviors are because we are still in the beginning.  Until now I haven’t provided any code examples. So let's take a brief of what is a class and what is an object:

The class: A building block that contains the properties and functionalities that describe some group of objects. We can create a class Person that contains:

  1. The properties of any normal person on the earth like: hair color, age, height, weight, eye color.
  2. The functionalities or behaviors of any normal person on the earth like: drink water, eat, go to the work.

Later we will see how we can implement the functionalities or behaviors and properties.

There are 2 kinds of classes: The built-it classes that come with the .NET Framework, called Framework Class Library, and the programmer defined-classes which we create ourselves.

The class contains data (in the form of variables and properties) and behaviors (in the form of methods to process these data). We will understand this concept later on in the article.

When we declare a variable in a class we call it member variables or instance variables. The name instance come from the fact that when we create an object we instantiate a class to create that object.  So instance of a class means an object of that class and instance variable means variable that exists in that class.

The object: It's an object of some classification (or class, or type) and when you create the object you can specify the properties of that object. What I mean here is: I, as an object, can have different properties (hair color, age, height, weight) than you as another object. For example, I have brown eyes and you have green eyes.  When I create 2 objects I will specify a brown color for my object's eye color property and I will specify a green color for your object's eye color property.

So to complete my introduction to classes we must discuss properties and variables.

Introduction to Objects and Classes in C# - Properties and Variables
(Page 5 of 9 )

Variables declared in a class store the data for each instance.  What does this mean? It means that when you instantiate this class (that is, when you create an object of this class) the object will allocate memory locations to store the data of its variables. Let's take an example to understand it well.

class Person
{
   public int Age;
   public string HairColor;
}

This is our simple class which contains 2 variables. Don't worry about public keyword now because we will talk about it later. Now we will instantiate this class (that is, when you create an object of this class).

static void Main(string[] args)
{
   Person Michael = new Person();
   Person Mary = new Person();

   // Specify some values for the instance variables
   Michael.Age = 20;
   Michael.HairColor = "Brown";
   Mary.Age = 25;
   Mary.HairColor = "Black";
   // print the console's screen some of the variable's values
   Console.WriteLine("Michael's age = {0}, and Mary's age = {1}",Michael.Age,
       Mary.Age);
   Console.ReadLine();
}

So we begin our Main method by creating 2 objects of type Person. After creating the 2 objects we initialize the instance variables for object Michael and then for object Mary. Finally we print some values to the console.  Here, when you create the Michael object, the C# compiler allocates a memory location for the 2 instance variables to put the values there. Also, the same thing with the Mary object; the compiler will create 2 variables in memory for Mary object. So each object now contains different data. Note that we directly accessed the variables and we put any values we wanted, right?  But wait there is a solution to this problem. We will use properties.

Introduction to Objects and Classes in C# - Properties
(Page 6 of 9 )

Properties are a way to access the variables of the class in a secure manner. Let's see the same example using properties.

class Person
{
   private int age;
   private string hairColor;
   public int Age
   {
       get
       {
       return age;
       }
       set
       {
           if(value <= 65 && value >= 18)
           {
               age = value;
           }
           else
               age = 18;
       }
   }
   public string HairColor
   {
       get
       {
           return hairColor;
       }
       set
       {
           hairColor = value;
       }
   }
}

I made some modifications, but focus on the new 2 properties that I created. So the property consists of 2 accessors. The get accessor, responsible of retrieving the variable value, and the set accessor, responsible of modifying the variable's value. So the get accessor code is very simple. We just use the keyword return with the variable name to return its value. So the following code:

get
  {
   return hairColor;
  }

returns the value stored in hairColor.

[Note]

The keyword value is a reserved keyword by C# (that is, reserved keywords means that these keywords are owned only by C# and you can't create it for any other purposes. For example, you can't create a variable called value .If you did, the C# compiler would generate an error. To make things easier, Visual Studio.NET will color the reserved keywords in blue.)

[/Note]

Let's put this code to work and then discuss the set accessor..

Introduction to Objects and Classes in C# - Reworked
(Page 7 of 9 )

static void Main(string[] args)
{
   Person Michael = new Person();
   Person Mary = new Person();

   // Specify some values for the instance variables
   Michael.Age = 20;
   Michael.HairColor = "Brown";
   Mary.Age = 25;
   Mary.HairColor = "Black";

   // print the console's screen some of the variable's values
   Console.WriteLine("Michael's age = {0}, and Mary's age = {1}",Michael.Age,
       Mary.Age);
   Console.ReadLine();
}

Here I created the same objects from the last example, except that I used only properties to access the variable instead of accessing it directly. Look at the following line of code

Michael.Age = 20;

When you assign a value to the property like that C# will use the set accessor. The great thing with the set accessor is that we can control the assigned value and test it; and maybe change to in some cases. When you assign a value to a property C# changes the value in a variable and you can access the variable's value using the reserved keyword value exactly as I did in the example. Let's see it again here.

set
  {
      if(value <= 65 && value >= 18)
      {
          age = value;
      }
      else
          age = 18;
  }

Here in the code I used if statement to test the assigned value because for some reason I want any object of type Person to be aged between 18 and 65. Here I test the value and if it is in the range then I will simply store it in the variable age. If it's not in the range I will put 18 as a value to age.

Introduction to Objects and Classes in C# - Creating Objects and Classes
(Page 8 of 9 )

We create a class by defining it using the keyword class followed by the class name:

class Person

Then we open a left brace "{" and write our methods and properties.  We then close it with a right brace "}". That's how we create a class. Let's see how we create an instance of that class.

In the same way as we declare a variable of type int we create an object variable of Person type with some modifications:

int age;
Person Michael = new Person();

In the first line of code we specified integer variable called age. In the second line we first specified the type of Object we need to create, followed by the object's name, followed by a reserved operator called new.  We end by typing the class name again followed by parentheses "()".

Let's understand it step-by-step. Specifying the class name at the beginning tells the C# Compiler to allocate a memory location for that type (the C# compiler knows all the variables and properties and methods of the class so it will allocate the right amount of memory). Then we followed the class name by our object variable name that we want it to go by. The rest of the code "= new Person();" calls the object's constructor. We will talk about constructors later but for now understand that the constructor is a way to initialize your object's variable while you are. For example, the Michael object we created in the last section can be written as following :

Person Michael = new Person(20, "Brown");

Here I specified the variable's values in the parameter list so I initialized the variables while creating the object. But for this code to work we will need to specify the constructor in the Person class -- I will not do that yet as constructors will come in a later article.

Introduction to Objects and Classes in C# - Conclusion
(Page 9 of 9 )

In this article, I gave you a concise introduction to classes and objects. I will complete the discussion in my next article, as well as discuss constructors and building block scope. I hope you’ve learned something new thing from this first article.

Introduction to Objects and Classes in C#, Part 2
(Page 1 of 4 )

After I wrote the article named Introduction to Objects and Classes in C#, I got a lot of e-mail messages asking me to create a series of articles about Objects and Classes. Actually this was a few months back (sorry for being late), but I'm here again with part two. In Part one, I explained the concepts behinds Objects and Classes but I didn't discuss why Object Oriented Programming (OOP) uses the Object and Class technique. Today, I will discuss the advantage of Objects and Classes with more details on how to understand your problems and develop your Objects for your solution.

Because this series targets the true beginners, I will not use any technical expressions and I will prefer to explain concepts by examples. I presume that readers have a basic knowledge of C# (control the flow of the program, using methods and arrays, namespaces & assemblies).

The first thing that you should know about C# programming is that it uses the Class to include the data (in part one, I said that data can be stored in instance variables in the class) and methods to process that data. Think about it in the next example:

class Test
{
   
public int Add(int x, int y)
   
{
       
return x + y;
   
}
}

The class Test contains a method called Add (which add to integers and return the result) is a good example for what we are talking about. I said that the Class includes data and there are methods to process that data, here the class test includes the method Add() which takes two integer numbers to add them and this is the functionality of the method. The application that will use the Test class can be something like the following:


public

class Class1
{
   
public Class1()
   
{
       Test t1
= new Test();
       Console
.WriteLine(t1.Add(5,4));
   
}
}

The concept of Objects & Classes helps you hide your code implementation from the user of your class. In other words, if you develop a class for your friend to use, he doesn't have to know how you created the methods of that class in order to use it; he'll just need to know how to use it, and what functionality is offered by your class members. The point here is that you don't have to know how another developer developed a certain class; you just have to know how to interface with it. And I said in the first part, when you develop programs with C# you will develop classes. Note that this is not like C programming, where the programming primary building block was the function (or methods, in C#). Finally, remember that C# defines other types like structures, enumerations. We'll learn about these in future articles.

In C programming language, programmers develop functions to form their applications. These functions contain the code of the program. The problem is that in large programs, if you have to modify just one line of code you may have to modify many functions to fit in the new modifications. (In procedural languages, functions depend on each other.) But in C#, we write classes as our primary building blocks, and because classes hide their code implementation -- and only the methods of these classes are accessible to the applications that use them -- if we must change something inside the class, we will do it without changing the code of the applications that uses our classes.

Introduction to Objects and Classes in C#, Part 2 - Comments
(Page 2 of 4 )

When you write applications in C# try to use comments to describe exactly how your application performs and why; try to make your application easy to understand and easy to maintain. Think about it this way: if you were to come back to your application five years after you wrote it, would you know what every line of code meant and did? What if someone was developing an application and they were trying to read through your code? Without documentation, this is difficult even for the most experienced programmers.  

I think that you want to know more about classes so let's write a class and then discuss  new concepts.

The Person Class

Here's a simple class called Person


class Person

{

   
// These are 3 private instance variables
   // for now just consider them instance members of
   // that class
   private string firstName;
   private string lastName;
   private int age;

   // This called the default constructor
   public Person()
   {

       
firstName = "Unknown";
       lastName
= "Unknown";
       age
= 0;

   }
   
   
// This also a Constructor and we will understand
   // the use of it and why we create constructors
   public Person(string fName, string lName, int pAge)
   {
       firstName = fName;
       lastName = lName;
       age = pAge;
   }

// This is a method just writes a string to the console.
// this string consists of the 3 variables and
// displaying the information about the person.
public void PersonInfo()
{

Console.WriteLine("First Name = {0}, Last Name = {1} and his age = {2}",
firstName
, lastName, age);

}

}

Let's break this down:

You're probably curious about private string firstName, private string lastName, and private int age. These are called instance variables, and as you know from the first part of that article, when you create objects from a given class (for example, the person class) you create an instance of that class. That's why we call the variables declared the body of the class (but not inside any method of that class) an instance variable. When you create an objects of that class C# compiler will allocate separate memory locations for the instance variables of each object. Thus, the object named Michael (of type Person) will contain its own values for these instance members, as will the object Prakhar (of type Person). You can say that the consumer application (the application that will use your class) will provide the values of these instance variables for each object created of that type.

NOTE About the keywords private and public in the class, they called access modifier keywords. When developing C# class you will use the access modifier keywords to specify the scope of the member. Each instance variable, method, or any other type you create inside a class called a member. C# gives you the power to specify the scope of the member using these access modifiers.

Introduction to Objects and Classes in C#, Part 2 - What's a Scope?
(Page 3 of 4 )

Simply, the scope of a type (a variable, a method, or a class) is where you can use that type in your program. In other words, the scope defines the area of the program where that type can be accessible and referenced.

When you declare a variable inside a block of code (like a method or an if statement structure), it will have a local scope, and it will be called a local-variable. Local scope means that you can't refer to that variable outside that block of code. Consider the next example.


class Test

{
   
public void Test1()
   
{
       int x 
= 0;
           
// some code goes here that uses the x variable
   }
   
   
public void Test2()
   
{
       Console
.WriteLine(x);
   
}
}


Try to instantiate this class and you will get a compile-time error inside method Test2() telling you that the name x doesn't exist and that's because x is a local variable to the method Test1() and method Test2() doesn't know anything about it. So x has a local score to method Test1() only. Consider the next example.


class Test

{

   public
void Test1()
   
{
       int x 
= 0;

       if(
x == 0)
       
{

           
Console.WriteLine("x equal to 0");
       
}
   
}
}

Here, the method Test1() declares a local variable x (now x has a local-scope to the method). Try to instance this class and compile the code. It will work! Some beginners think that because I said that x has a local scope to method Test1() it will not be referenced from nested block (like the one we have here, the If statement) but that's not true because any nested block inside Test1() method can refer x because x is local for the method and its all blocks of code.

NOTE  There are 2 kinds of scopes: block scope (the one that we just finished), and a class scope (which we will talk about later in this article). Now, about the keywords private and public in the class person, you can use these access modifier keywords to define the scope of your variables, methods, or even your classes. There are other access modifiers but I will talk about them in a later article when I will explain the concepts of inheritance.

Instance variables declared using the access modifier keyword private will be accessible to the methods between the opening left brace "{" and the closing right brace "}" (which define the body of the class) only. In other words, when you declare an instance variable like in the following example:


public

class Class2
{
   
private int x;
}

public class
Class3
{
   void testing
()
   
{
       x
== 100;
   
}
}

In this example, you will get a compile-time error telling you that you that the name X doesn't exist inside the Class3. Using the keyword private, you explicitly tell the compiler "Don't show this member to any other class." (So you are hiding it inside the class.)

Introduction to Objects and Classes in C#, Part 2 - Private Members Only?
(Page 4 of 4 )

What about objects of that class? Can they access the members declared as private?

In short, no, the objects of this class will not see the private member, but it will have it's own copy because as we said before the class is just a template for the contents of its object. I prefer to discuss it using an example:


public

class Class2
{
   
private int x = 100;
}

And then I will instance 2 objects of that class inside the Main method


static void Main

(string[] args)
{
   Class2 c2
= new Class2();
   Class2 c3
= new Class2();
   
// Now Let's check if we can see
   // x inside any of these objects
   c2.
}

c2 and c3 are objects of type Class2() but look what happened when I typed the "." operator (which will get us all the accessible members of that class).

C#

There is no x here because it's private to the class. You may wonder why this feature exists. Sometimes you need to hide some values inside the class (ie. you don't want other classes or objects of that class to see these values), maybe because it's complex information, or it's private to your work, or the developers that will use your class (after it's compiled) will simply not benefit if they saw these variables or methods.

You can use the access modifier keyword public while you declare your variables to specify that you want your variable to be accessed by the other classes or any objects of this class. let's revise the the x variable in Class2 and check if we can see it or not (from objects of this class or other classes).


public

class Class2
{
   
public int x = 100;
}

Now let's see the result:

C#

Oh, yes we can see the x variable now because we made it public. And I will talk about Class Scope in a later article. For now, just play around with scopes. I think you'll have a lot of fun with these.

"C#" 카테고리의 다른 글
  • Introduction to Objects and Classes in C# (0)2007/07/27
  • Creational Patterns in C# (0)2007/07/27
  • Exception Handling in C# (0)2007/07/27
  • C# 키워드 목록 (0)2007/07/02
  • Event Handling in .NET Using C# (0)2007/06/26
2007/07/27 09:27 2007/07/27 09:27
Posted by webdizen
Tags C#, Classes, Objects
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3100

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Network Programming2007/07/27 09:22

Socket Programming in C#

출처 : http://www.devarticles.com/c/a/c-sharp/ ··· art-i%2F

Socket Programming in C# - Part I
(Page 1 of 2 )

If you have dealt with sockets in the past, you may be interested in learning how it is done using C# technology. Read more ...The purpose of this article is to show you how you can do socket programming in C#. This article assumes some familiarity with the socket programming, though you need not to be expert in socket programming. There are several flavors to socket programming - like client side , server side , blocking or synchronous , non-blocking or asynchronous etc.

With all these flavors in mind , I have decided to break this subject into two parts. In the part 1 I  will start with the client side blocking socket. Later on in the second part I will show you how to create server side and non-blocking.


Socket Programming in C# - Part I - The Article
(Page 2 of 2 )

Network programming in windows is possible with sockets. A socket is like a handle to a file. Socket programming resembles the file IO as does the Serial Communication. You can use sockets programming to have two applications communicate with each other. The application are typically on the different computers but they can be on same computer. For the two applications to talk to each either on the same or different computers using sockets one application is generally a server that keeps listening to the incoming requests and the other application acts as a client and makes the connection to the server application.

The server application can either accept or reject the connection. If the server accepts the connection, a dialog can begin with between the client and the server.  Once the client is done with whatever it needs to do it can close the connection with the server. Connections are expensive in the sense that servers allow finite connections to occur.  During the time client has an active connection it can send the data to the server and/or receive the data.

The complexity begins here. When either side (client or server) sends data the other side is supposed to read the data. But how will the other side know when data has arrived. There are two options - either the application needs to poll for the data at regular intervals or there needs to be some sort of mechanism that would enable application to get notifications and application can read the data at that time. Well , after all Windows is an event driven system and the notification system seems an obvious and best choice and it in fact is.

As I said the two applications that need to communicate with each other   need to make a connection first. In order for the two application to make connections the two applications need to identify each other ( or each other's computer ). Computers on network have a unique identifier called  I.P. address which is represented in dot-notation like 10.20.120.127 etc. Lets see how all this works in .NET.

System.Net.Sockets Namespace

Before we go any further, download the source code attached with this article. Extract the zip file to a folder say c:\Temp you will see following two folders :

  • Server
  • Client

In the Server folder there will be one EXE . And in the client there will be the source code in C# that is our client. There will be one file called SocketClient.sln  which the solution file . If you double click that your VS.NET will be launched and you will see the  project SocketClientProj in the solution. Under this project you will have SocketClientForm.cs file.  Now build the code ( by pressing Ctrl-Shift-B) and run the code you will see the following dialog box:

As you can see the dialog box has a field for Host IP address ( which is the IP address of the machine on which you will run the Server Application ( located under Server folder) ). Also there is a field where you can specify port number at which the Server is listening. The server app I have provided here listens at port 8221. So I have specified port to be 8221.


After specifying these parameters we need to connect to the server. So pressing Connect will connect to the server and to close the connection press Close. To send some data to the server type some data in the field near the button name Tx and if you press Rx the application will block unless there is some data to read.
With this info lets now try to check the code behind this:

Socket programming in .NET is made possible by Socket class present inside the System.Net.Sockets namespace.
Socket class  has several method and properties and a constructor.
The first step is to create an object of this class.
Since there is only one constructor we have no choice but to use it.

Here is how to create the socket:

m_socListener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.IP);

The first parameter is the address family which we will use interNetwork - other options include Banyan NetBios etc.
AddressFamily is an enum defined in Sockets namespace.
Next we need to specify socket type: and we would use reliable two way connection-based sockets (stream) instead of un-reliable Connectionless sockets ( datagrams) . So we obviously specify stream as the socket type and finally we are using TCP/IP so we would specify protocol type as Tcp.

Once we have created a Socket we need to make a connection to the server since we are using connection-based communication.
To connect to the remote computer  we need to know the IP Address and port at which to connect.
In .NET there is a class under System.Net namespace called IPEndPoint which represents a network computer  as an IP address and a port number.

The IPEndPoint has two  constructors - one that takes a IP Address and Port number  and one that takes long and port number. Since we have computer IP address we would use the former

public IPEndPoint(System.Net.IPAddress address, int port);

As you can see the first parameter takes a IPAddress object. If you examine the IPAddress class you will see that it has a static method called Parse that returns IPAddress given a string ( of dot notation ) and second parameter will be the port number. Once we have endpoint ready we can use Connect method of Socket class to connect to the end point  ( remote server computer ).
Here is the code:

System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse("10.10.101.200");
System.Net.IPEndPoint remoteEP = new IPEndPoint (iAdd,8221);
m_socClient.Connect (remoteEP);

These three lines of code will make a connection to the remote host running on computer with IP 10.10.101.200 and listening at port 8221. If the Server is running and started ( listening ), the connection will succeed. If however the server is not running an exception called SocketException will be thrown. If you catch the   exception and check the Message property of the exception in this case you see following text:

"No connection could be made because the target machine actively refused it."

Similarly if you already have made a connection and the server somehow dies , you will get following exception if you try to send data.

"An existing connection was forcibly closed by the remote host"

Assuming that the connection is made, you can send data to other side using the Send method of the Socket class.
Send method has several overloads. All of them take a byte array . For example if you want to send "Hello There" to host you can use following call:

try
{
String szData = "Hello There";
byte[] byData = System.Text.Encoding.ASCII.GetBytes(szData);
m_socClient.Send(byData);
}
catch (SocketException se)
{
MessageBox.Show ( se.Message );
}

Note that the Send method is blocking. What it means the call will block till the data has been sent or an exception has been thrown. There is an non-blocking version of the send which we will discuss in the next part of this article.
Similar to Send there is a Receive method on the Socket class. You can receive data using following call:

byte [] buffer = new byte[1024];
int iRx = m_socClient.Receive (buffer);

The Receive method again is blocking. It means that if there is no data available the call will block until some data arrives or an exception   is thrown.

Non-blocking version of Receive method is more useful than the non-blocking version of Send because if we opt for block Receive , we are effectively doing polling. There is no events about data arrival. This model does not work well for serious applications. But all that is the subject of our next part of this article. For now we will settle with the blocking version.
In order to use the source code and application here you would need to run the Server first:

Here is the way Server looks like:

When you launch the Server, click Start to start listening. The Server listens at port 8221. So make sure you specify the port number 8221 in the port field of our client application. And in the IPAddress field of Client App enter the IP Address of the machine on which the Server is running. If you send some data to server from the client by pressing Tx button, you will see that data in the grayed out edit box.


Socket Programming in C# - Part II
(Page 1 of 2 )

This is the second part of Ashish's two part series about handling sockets in the C# language. Read this article to learn how to use sockets with the .Net framework.This is the second part of the previous article about the socket programming. In the earlier article we created a client but that client used to make blocking IO calls ( Receive ) to read data at regular intervals (via clicking the Rx button). But as I said in my earlier article, that model does not work very well in a real world application. Also since Windows is an events-based system, the application (client) should get notifications of some kind whenever the data is received so that client can read it rather than client continuously polling for data.

Well that is possible with a little effort. If you read the first part of this article, you already know that the  Socket class in  the Systems.Net.Sockets namespace has several methods like  Receive and Send which are blocking calls. Besides there are also functions like BeginReceive , BeginSend etc. These are meant for asynchronous IO . For example , there are at least two problems with the blocking Receive:

  1. When you call Receive function the call blocks if no data is present, the call blocks till some data arrives.
  2. Even if there is data when you made the receive call , you don't know when to call next time. You need to do  polling  which is not an efficient way.
Socket Programming in C# - Part II - Article
(Page 2 of 2 )

 

Although you can argue that one can overcome these shortcomings by multithreading meaning that one can spawn a new thread and let that thread do the polling and notifies the main thread of the data. Well this concept will work well. But even if you create a new thread it would require your main thread to share the CPU time with this new thread. Windows operating system (Windows NT /2000 /XP) provide what is called Completion Port IO model for doing overlapped ( asynchronous) IO.

The details of IO Completion port are beyond the scope of the current discussion, but to make it simple you can think of IO Completion Ports as the most efficient mechanism for doing asynchronous IO in Windows that is provided by the Operating system. Completion Port model can be applied to any kind of IO including the file read /write and serial communication.  

The .NET asynchronous socket programming helper class's Socket provides the similar model.  

BeginReceive
 

.NET framework's Socket class provides BeginReceive method to receive data asynchronously i.e., in an non-blocking manner The BeginReceive method has following signature:

public IAsyncResult BeginReceive( byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state );

The way BeginReceive function works is that you pass the function a buffer , a callback function (delegate)   which will be called whenever data arrives.

The last parameter,  object,   to the BeginReceive can be any class derived from object  ( even null ) .
When the callback function is called it means that the BeginReceive function completed which means that the data has arrived.
The callback function needs to have the following signature:

void AsyncCallback( IAsyncResult ar);

As you can see the callback returns void and is passed in one parameter , IAsyncResult interface , which contains  the status of the asynchronous receive  operation.

The IAsyncResult interface has several properties. The first parameter - AsyncState - is an object which is same as the last parameter that you passed to BeginReceive(). The second  property is AsyncWaitHandle which we will discuss in a moment. The third property indicates whether the receive was really asynchronous or it finished synchronously. The important thing to follow here is that it not necessary for an asynchronous function to always  finish asynchronously - it can complete immediately if the data is already present. Next parameter is IsComplete   which indicates whether the operation has completed or not.

If you look at the signature of the BeginReceive again you will note that the function also returns IAsyncResult. This is interesting. Just now I said that I will talk about the second peoperty of the IAsyncResult  in a moment. Now is that moment. The second parameter is called AsyncWaitHandle.

The AsyncWaitHandle is of type WaitHandle, a class defined in the System.Threading namespace. WaitHandle class encapsulates a Handle (which is a pointer to int or handle ) and provides a way to wait for that handle to become signaled. The class has several static methods like WaitOne ( which is similar to WaitForSingleObject ) WaitAll ( similar to WaitForMultipleObjects with waitAll true ) , WaitAny etc. Also there are overloads of these functions available with timeouts.

Coming back to our discussion of IAsyncResult interface, the handle in AsyncWaitHandle (WaitHandle) is signalled when the receive operation completes. So if we wait on that handle infinitely we will be able to know when the receive completed. This means if we pass that WaitHandle to  a different thread, the different thread can wait on that handle and can notify us of the fact that the data has arrived and so that we can read the data. So you must be wondering if we use this mechanism why would we use callback function. We won't. Thats right. If  we choose to use this mechanism of the WaitHandle then the callback function parameter to the BeginReceive can be null as shown here:

//m_asynResult is  declared of type IAsyncResult and assumming that m_socClient has made a connection.
m_asynResult = m_socClient.BeginReceive(m_DataBuffer,0,m_DataBuffer.Length,SocketFlags.None,null,null);
if ( m_asynResult.AsyncWaitHandle.WaitOne () )
{
int iRx = 0 ;
iRx = m_socClient.EndReceive (m_asynResult);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(m_DataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
txtDataRx.Text = txtDataRx.Text + szData;
}

Even though this mechanism will work fine using multiple threads, we will for now stick to our callback mechanism where the system notifies us of the completion of asynchronous operation which is Receive in this case .
Lets say we made the call to BeginReceive and after some time the data arrived and our callback function got called.Now question is where's the data? The data is now available in the buffer that you passed as the first parameter while making call to BeginReceive() method . In the following example the data will be available in m_DataBuffer :

BeginReceive(m_DataBuffer,0,m_DataBuffer.Length,SocketFlags.None, pfnCallBack,null);

But before you access the buffer you need to call EndReceive() function on the socket. The EndReceive will return the number of bytes received . Its not legal to access the buffer before calling EndReceive.
To put it all together  look at the following simple code:

byte[] m_DataBuffer = new byte [10];
IAsyncResult m_asynResult;
public AsyncCallback pfnCallBack ;
public Socket m_socClient;
// create the socket...
public void OnConnect()
{
m_socClient = new Socket (AddressFamily.InterNetwork,SocketType.Stream ,ProtocolType.Tcp );
// get the remote IP address...
IPAddress ip = IPAddress.Parse ("10.10.120.122");
int iPortNo = 8221;
//create the end point
IPEndPoint ipEnd = new IPEndPoint (ip.Address,iPortNo);
//connect to the remote host...
m_socClient.Connect ( ipEnd );
//watch for data ( asynchronously )...
WaitForData();
}
public void WaitForData()
{
if ( pfnCallBack == null )
pfnCallBack = new AsyncCallback (OnDataReceived);
// now start to listen for any data...
m_asynResult =
m_socClient.BeginReceive (m_DataBuffer,0,m_DataBuffer.Length,SocketFlags.None, pfnCallBack,null);
}
public void OnDataReceived(IAsyncResult asyn)
{
//end receive...
int iRx = 0 ;
iRx = m_socClient.EndReceive (asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(m_DataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
WaitForData();
}


The OnConnect function makes a connection to the server and then makes a call to WaitForData. WaitForData creates the callback function and makes a call to BeginReceive passing a global buffer and the callback function. When data arrives the OnDataReceive is called and the m_socClient's EndReceive is called which returns the number of bytes received and then the data is copied over to a string and a new call is made to WaitForData which will call BeginReceive again and so on.  This works fine if you have one socket in you application.  

MULTIPLE SOCKETS

Now lets say you have two sockets connecting to either two different servers or same server(which is valid) . One way is to create two different delegates and attach a different delegate to different BeginReceive function. What if you have 3 sockets or for that matter n sockets , this approach of creating multiple delegates does not fit well in such cases. So the solution should be to use only one delegate callback. But then the problem is how do we know what socket completed the operation.

Fortunately there is a better solution. If you look at the BeginReceive function again, the last parameter is  a state is an object. You can pass anything here . And whatever you pass here will be passed back to you later as the part of parameter to the callback function. Actually this object will be passed to you later as a IAsyncResult.AsyncState. So when your callback gets called, you can use this information to identify the socket that completed the operation. Since you can pass any thing to this last parameter, we can pass a class object that contains as much information as we want. For example we can declare a class as follows:

public class CSocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[1024];
}

and call BeginReceive as follows:

CSocketPacket theSocPkt = new CSocketPacket ();
theSocPkt.thisSocket = m_socClient;
// now start to listen for any data...
m_asynResult = m_socClient.BeginReceive (theSocPkt.dataBuffer ,0,theSocPkt.dataBuffer.Length , SocketFlags.None,pfnCallBack,theSocPkt);

and in the callback function we can get the data like this:

public void OnDataReceived(IAsyncResult asyn)
{
  try
  {
CSocketPacket theSockId = (CSocketPacket)asyn.AsyncState ;
//end receive...
int iRx = 0 ;
iRx = theSockId.thisSocket.EndReceive (asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
txtDataRx.Text = txtDataRx.Text + szData;
WaitForData();
  }
  catch (ObjectDisposedException )
  {
System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket has been closed\n");
  }
  catch(SocketException se)
  {
MessageBox.Show (se.Message );
  }
}

To see the whole application download the code and you can see the code.

There is one thing which you may be wondering about. When you call BeginReceive , you have to pass a buffer and the number of bytes to receive. The question here is how big should the buffer be. Well, the answer is it depends. You can have a very small buffer size say, 10 bytes long and if there are 20 bytes ready to be read, then you would require 2 calls to receive the data. On the other hand if you specify the length as 1024 and you know you are always going to receive data in 10-byte  chunks you are unnecessarily wasting memory. So the length depends upon your application.

Server Side

If you have understood whatever I have described so far, you will easily understand the Server part of the socket application. So far we have been talking about a client making connection to a server and sending and receiving data.

On the Server end, the application has to send and receive data. But in addition to adding and receiving data, server has to allow the clients to make connections by listening at some port. Server does not need to know client I.P. addresses. It really does not care where the client is because its not the server but client who is responsible for making connection. Server's responsibility is to manage client connections.

On the server side there has to be one socket called the Listener socket that listens at a specific port number for client connections. When the client makes a  connection, the server needs to accept the connection and then in order for the server to send and receive data from that connected client it needs to talk to that client through the socket that it got when it accepted the connection . Following code illustrates how server listens to the connections and accepts the connection:

public Socket m_socListener;
public void StartListening()
{
try
{
//create the listening socket...
m_socListener = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint ( IPAddress.Any ,8221);
//bind to local IP Address...
m_socListener.Bind( ipLocal );
//start listening...
m_socListener.Listen (4);
// create the call back for any client connections...
m_socListener.BeginAccept(new AsyncCallback ( OnClientConnect ),null);
cmdListen.Enabled = false;
}
catch(SocketException se)
{
MessageBox.Show ( se.Message );
}
}

If you look at the above code carefully you will see that its similar to we did in the asynchronous client. First of all the we need to create a listening socket and bind it to a local IP address. Note that we have given Any as the IPAddress . I will explain what it means later. and also we have passed port number as 8221. Next we made a call to Listen function. The 4 is a parameter indicating backlog indicating the maximum length of the queue of pending connections.

Next we made a call to BeginAccept passing it a delegate callback. BeginAccept is a non-blocking method that returns immediately and when a client has made requested a connection, the callback routine is called and you can accept the connection by calling EndAccept. The EndAccept returns a socket object which represents the incoming connection. Here is the code for the callback delegate:

public void OnClientConnect(IAsyncResult asyn)
{
try
{
  m_socWorker = m_socListener.EndAccept (asyn);
WaitForData(m_socWorker);
}
catch(ObjectDisposedException)
{
             System.Diagnostics.Debugger.Log(0,"1","\n OnClientConnection: Socket has been closed\n");
}
catch(SocketException se)
{
MessageBox.Show ( se.Message );
}
}

Here we accept the connection and call WaitForData which in turn calls BeginReceive for the m_socWorker.

If we want to send data  some data to client we use m_socWorker socket for that purpose like this:

Object objData = txtDataTx.Text;
byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString ());
m_socWorker.Send (byData);

Here is how our client looks like

Here is how our server looks like

That is all there is to the socket programming.


"Network Programming" 카테고리의 다른 글
  • Socket Programming in C# (0)2007/07/27
  • Network Programming in C# (0)2007/07/27
  • IOCP Thread Pooling in C# (0)2007/07/26
  • UDP 프로그래밍의 기초 (0)2007/05/14
  • ICMP 프로그래밍 (0)2007/05/14
2007/07/27 09:22 2007/07/27 09:22
Posted by webdizen
Tags C#, Socket
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3099

Leave your greetings.

[로그인][오픈아이디란?]

Programming/C#2007/07/27 09:18

Creational Patterns in C#

출처 : http://www.devarticles.com/c/a/c-sharp/ ··· sharp%2F

Creational Patterns in C#
(Page 1 of 6 )

When it comes to asking questions about creating patterns with C#, Rajesh has all the answers. Read about some C# patterns in this article.

The software design patterns are mainly classified into three categories, namely Creational Patterns, Structural Patterns and Behavioral Patterns. The Creational Patterns deals with the best way to create objects. The Singleton Pattern is an example of Creational Pattern.

The singleton design pattern is used when only one instance of an object is needed throughout the lifetime of an application. The singleton class is instantiated at the time of first access and the same instance is used thereafter till the application quits.

The famous GOF defined the Singleton Pattern as follows.

“Ensure a class has only one instance, and provide a global point of access to it.” -- "Design Patterns” Gamma et al., Addison-Wesley, ISBN:0-201-63361-2”

The Singleton class can be used in various places where one would need a common repository of information that can be accessed from all objects in an application. For example sometimes we may need a single Database connection object or Network connection object.

Non-software Example

The office of the President of the United States is a Singleton. The United States Constitution specifies the means by which a president is elected, limits the term of office, and defines the order of succession. As a result, there can be at most one active president at any given time. Regardless of the personal identity of the active president, the title, "The President of the United States" is a global point of access that identifies the person in the office. [Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p54]

It is pretty easy to implement the Singleton Pattern in C#. There are lots trivial ways to achieve this. But by using a private constructor and a static method to create an instance of the class is a popular way to create singleton pattern.

The above program will display OK and then followed by NO MORE OBJECTS. The value of the object sic2 is null, because we can’t create two or more instances of the class SingleInstanceClass.

C# Implementation

//Creational Pattern: SINGLETON
//Implemenation in C#
//By
rajeshvs@msn.com
/*The constructor should be private. Provide a static method, which returns an instance of the class. use a static variable to check whether already one instance is created or not. if already an instance is there , returns a null */
using System;
class SingleInstanceClass
{
private static SingleInstanceClass sic= null;
private static bool instanceFlag = false;

private SingleInstanceClass()
{
}
public static SingleInstanceClass Create()
{
 if(! instanceFlag)
 {
  sic = new SingleInstanceClass();
  instanceFlag = true;
  return sic;
 }
 else
 {
  return null;
 }
}
protected void Finalize()
{
 instanceFlag = false;
}
}
class MyClient
{
public static void Main()
{
 SingleInstanceClass sic1,sic2;
 sic1 = SingleInstanceClass.Create();
 if(sic1 != null)
  Console.WriteLine("OK");
 sic2 = SingleInstanceClass.Create();
 if(sic2 == null)
  Console.WriteLine("NO MORE OBJECTS");
}
}

The above program returns a null value when try to create an object second time. But instead of returning null, it is possible to return already existing object ‘sic’ by changing ‘return null’ to ‘return sic’ in the above program.

Creational Patterns in C# - The Factory Method Pattern
(Page 2 of 6 )

The Factory Method Pattern comes under the classification of Creational Patterns. The creational patterns deals with the best way to create objects. The Factory Method provides a simple decision making class that can return the object of one of several subclasses of an abstract base class depending on the information that are provided.

“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.” -- "Design Patterns” Gamma et al., Addison-Wesley, ISBN:0-201-63361-2”

Non-software Example

Injection molding presses demonstrate this pattern. Manufacturers of plastic toys process plastic molding powder, and inject the plastic into molds of the desired shapes. The class of toy (car, action figure, etc.) is determined by the mold. [Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p54]

A factory pattern is one that returns an instance of one of several possible classes depending on the data provided to it. Usually all of the classes it returns should have a common base class and common methods, but implementations of the methods may be different.

The following is an UML representation of the Factory Method Pattern. In this case we are not directly creating an instance of the class Derived1 and Derived2. Instead we are using the getObject() method of the Factory class to return an appropriate instance depending on the value passed to the getObject() method. This method is commonly knows as the Factory method and Factory method can be either static or non-static in nature.

C# Implementation

//Creational Pattern: The Factory Method
//Author:
rajeshvs@msn.com
/* In Factory method pattern, A Factory class contains a factory method is used for creating the object. This factory method can be either static or non-static. */
using System;
class Factory
{
public Base GetObject(int type)
{
 Base base1 = null;
 switch(type)
 {
  case 1:
    base1 = new Derived1();
    break;
  case 2:
    base1 = new Derived2();
    break;
 }
 return base1;
}
}
interface Base
{
  void DoIt();
}
class Derived1 : Base
{
   public void DoIt()
   {
 Console.WriteLine("Derived 1 method");
   }
}
class Derived2 : Base
{
   public void DoIt()
   {
 Console.WriteLine("Derived 2 method");
   }
}
//Client class
//Client class needn’t know about instance creation. The creation of Product is //deferred to the Factory class
class MyClient
{
   public static void Main()
   {
     Factory factory = new Factory();//Decides which object must create.
     Base obj = factory.GetObject(2);
     obj.DoIt();
   }
}

This is what the fundamental principle of Factory pattern. We create an abstraction, which decides which of several possible classes to return, and returns one. After that we can call the methods of that class instance without ever knowing which derived class is using actually. The object creation happens in a single place that is inside the Factory class.

Remember that the Factory class can contain more than one Factory methods. Even these Factory methods can be either static or non-static.

Creational Patterns in C# - The Abstract Factory Pattern
(Page 3 of 6 )

The Abstract Factory Pattern comes under the classification of Creational Patterns. The creational patterns deals with the best way to create objects. The Abstract Factory provides an interface to create and return one of several families of related objects.

“Provide an interface for creating families of related or dependent objects without specifying their concrete classes” -- "Design Patterns” Gamma et al., Addison-Wesley, ISBN:0-201-63361-2”

Non-software Example

This pattern is found in the sheet metal stamping equipment used in the manufacture of Japanese automobiles. The stamping equipment is an Abstract Factory, which creates auto body parts. The same machinery is used to stamp right hand doors, left hand doors, right front fenders, left front fenders, hoods, etc. for different models of cars. Through the use of rollers to change the stamping dies, the concrete classes produced by the machinery can be changed within three minutes.

[Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p54]

The abstract factory is a factory object that returns one of several factories. It can be used to return one of several related classes of objects, each of which can return several different objects on request.

The abstract factory pattern can be interpreted and implemented in many ways. The following is a simples interpretation and implementation of this pattern.

In this case the interface Factory has two concrete implementations, ConcreteFactory1 and ConcreteFactory2. The getObject() inside these concrete classes returns Derived1 and Derived2 objects respectively. The client can decide which ConcreteFactory class has to be used during the run-times.

The following is a more complicated interpretation and implementation of this pattern. Here those Factory class methods are used for returning objects of two different class hierarchies.

C# Implementation

// Creational Pattern: Abstract Factory Pattern
//Author:
rajeshvs@msn.com
/*
In the following snippet, Factory is an interface. The concrete implementation of this
interface ConcreteFactory1 and ConcreteFactory2 implements the method getObject so
that it returns Derived1 and Derived2 objects respectively. The Base is an interface and
Derived1 and Derived2 are the concrete implementations of the base class. The client
(MyClient class) always uses the Factory implementations to create an instance of the
Base classes. Actually the derived classes of Factory interface decided which object
(either Derived1 or Derived2) has to be created.
*/
using System;
interface Factory
{
  Base GetObject();
}
//This class is responsible for creating objects of the class Derived1.
class ConcreteFactory1 :Factory
{
  public Base GetObject()
  {
return new Derived1();  
  }
}
//This class is responsible for creating objects of the class Derived2.
class ConcreteFactory2 : Factory
{
  public Base GetObject()
  {
return new Derived2();  
  }
}
interface Base
{
  void DoIt();
}
class Derived1 : Base
{
  public void DoIt()
  {
Console.WriteLine("Derived 1 method");
  }
}
class Derived2 : Base
{
  public void DoIt()
  {
Console.WriteLine("Derived 2 method");
  }
}
/*
Client class Client class needn’t know about instance creation. The creation of Product
is  deferred to he ConcreteFactory1.
*/
class MyClient
{
  public static void Main()
  {
   Factory factory = new ConcreteFactory2();//Decides which object must create.
   Base obj = factory.GetObject();
   obj.DoIt();
  }
}

Creational Patterns in C# - The Builder Pattern
(Page 4 of 6 )

The Builder Pattern comes under the classification of Creational Patterns. The creational patterns deals with the best way to create objects. The Builder Pattern separates the construction of a complex object from its representation so that several different representations can be created depending on the needs of the program.

“Separate the construction of a complex object from its representation so that the same construction process can create different representations.” ” -- "Design Patterns” Gamma et al., Addison-Wesley, ISBN:0-201-63361-2”

Builder is an object creational design pattern that codifies the construction process outside of the actual steps that carries out the construction - thus allowing the construction process itself to be reused.

Non-software Example

Fast food restaurants to construct children’s meals use this pattern. Children's meals typically consist of a main item, a side item, a drink, and a toy (e.g., a hamburger, fries, Coke, and toy car). Note that there can be variation in the content of the children's meal, but the construction process is the same. Whether a customer orders a hamburger, cheeseburger, or chicken, the process is the same.

The employee at the counter directs the crew to assemble a main item, side item, and toy. These items are then placed in a bag. The drink is placed in a cup and remains outside of the bag. This same process is used at competing restaurants. [Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p54]

Another example for Builder pattern is a Computer Assembly. A computer is nothing but the bundling of various components like FDD, HDD, Monitor etc. But when an user buys a computer someone assemble all these components and given to us. Remember that here the building process is completely hidden from the client or user.

The UML diagram for a Builder pattern is more or less like following one.

Remember that a project can contain one or more builders and each builder is independent of others. This will improves the modularity and makes the addition of other builders relatively simple. Since each builder constructs the final product step by step, we have more control over the final product that a builder constructs.

C# Implementation

//Creational Pattern: BUILDER
//Author: rajeshvs@msn.com
using System;
class Director
{
public void Construct(IBuilder builder)
{
 builder.DoIt();
}
}
interface IBuilder
{
void DoIt();
}
class BuilderA : IBuilder
{
public void DoIt()
{
 //Necessary code for building the computer type A
 Console.WriteLine("Assembly a Computer with mono monitor");
}
}
class BuilderB : IBuilder
{
public void DoIt()
{
 //Necessary code for building the computer type B
 Console.WriteLine("Assembly a Computer with color monitor");
}
}
class MyClient
{
public static void Main()
{
 Director d = new Director();
 IBuilder build = new BuilderA();
 d.Construct(build);
}
}

Creational Patterns in C# - The Prototype Pattern
(Page 5 of 6 )

The Prototype Pattern comes under the classification of Creational Patterns. The creational patterns deals with the best way to create objects. This helps to copy or clone the existing objects to create new ones rather than creating from the scratch.

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype. -- "Design Patterns” Gamma et al., Addison-Wesley, ISBN:0-201-63361-2”

The prototype pattern is used when creating an instance of a class is very time consuming or complex in some way. Then rather than creating more instances, it is possible to make copies of the original instances and modifying them as appropriate.

When we are not in a position to call a constructor for an object directly, we could alternatively clone a pre-existing object  (a prototype) of the same class. When there are many subclasses that differ only in the kind of objects they create a Prototype Pattern can be used to reduce the number of subclasses by cloning a prototype. Prototype Design Pattern helps in reducing number of classes.

For example suppose we have to do say Sales Analysis on a set of data in the database. Normally we will create an object encapsulating this data and do the Sales Analysis. Suppose now we have to do another type of analysis say Promotion Analysis on the same data. Now instead of creating another object corresponds to the data from the scratch, we can clone the existing object and do the analysis. This is one of the classical use of prototype pattern.

Remember that in C#, this pattern can be implemented easily by using the clone(). Any class, which wants to support cloning, should inherit from the ICloneable interface in C#. ICloneable interface contains a Clone() method which we can override in our class. Clone can be implemented either as a deep copy or a shallow copy. In a deep copy, all objects are duplicated; whereas, in a shallow copy, only the top-level objects are duplicated and the lower levels contain references.

The resulting clone must be of the same type as or a compatible type to the original instance.

Creational Patterns in C# - Summary
(Page 6 of 6 )

The Singleton Pattern is a pattern that insures there are one and only one instance of an object, and that it is possible to obtain global access to that one instance.

The Factory Pattern is used to choose and return an instance of a class from a number of similar classes based on data you provide to the factory.

The Abstract Factory Pattern is used to return one of several groups of classes. In some cases it actually returns a Factory for that group of classes.

The Builder Pattern assembles a number of objects to make a new object, based on the data with which it is presented. Frequently, the choice of which way the objects are assembled is achieved using a Factory.

The Prototype Pattern copies or clones an existing class rather than creating a new instance when creating new instances is more expensive.

"C#" 카테고리의 다른 글
  • Introduction to Objects and Classes in C# (0)2007/07/27
  • Creational Patterns in C# (0)2007/07/27
  • Exception Handling in C# (0)2007/07/27
  • C# 키워드 목록 (0)2007/07/02
  • Event Handling in .NET Using C# (0)2007/06/26
2007/07/27 09:18 2007/07/27 09:18
Posted by webdizen
Tags C#, Pattern
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3098

Leave your greetings.

[로그인][오픈아이디란?]

Programming/C#2007/07/27 09:14

Exception Handling in C#

As we all know, exception handling becomes a very handy tool for debugging an application. Rajesh will now explein how one should use Exceptions in C#.

Exception handling is an in built mechanism in .NET framework to detect and handle run time errors. The .NET framework contains lots of standard exceptions. The exceptions are anomalies that occur during the execution of a program. They can be because of user, logic or system errors. If a user (programmer) do not provide a mechanism to handle these anomalies, the .NET run time environment provide a default mechanism, which terminates the program execution. 

C# provides three keywords try, catch and finally to do exception handling. The try encloses the statements that might throw an exception whereas catch handles an exception if one exists. The finally can be used for doing any clean up process.

The general form try-catch-finally in C# is shown below 

try
{
// Statement which can cause an exception.
}
catch(Type x)
{
// Statements for handling the exception
}
finally
{
//Any cleanup code
}

If any exception occurs inside the try block, the control transfers to the appropriate catch block and later to the finally block.  

But in C#, both catch and finally blocks are optional. The try block can exist either with one or more catch blocks or a finally block or with both catch and finally blocks. 

If there is no exception occurred inside the try block, the control directly transfers to finally block. We can say that the statements inside the finally block is executed always. Note that it is an error to transfer control out of a finally block by using break, continue, return or goto. 

In C#, exceptions are nothing but objects of the type Exception. The Exception is the ultimate base class for any exceptions in C#. The C# itself provides couple of standard exceptions. Or even the user can create their own exception classes, provided that this should inherit from either Exception class or one of the standard derived classes of Exception class like DivideByZeroExcpetion ot ArgumentException etc. 

Uncaught Exceptions

The following program will compile but will show an error during execution. The division by zero is a runtime anomaly and program terminates with an error message. Any uncaught exceptions in the current context propagate to a higher context and looks for an appropriate catch block to handle it. If it can’t find any suitable catch blocks, the default mechanism of the .NET runtime will terminate the execution of the entire program. 

//C#: Exception Handling
//Author:
rajeshvs@msn.com
   
using System;
class MyClient
{
           public static void Main()
           {
                       int x = 0;
                       int div = 100/x;
                       Console.WriteLine(div);
           }
}

The modified form of the above program with exception handling mechanism is as follows. Here we are using the object of the standard exception class DivideByZeroException to handle the exception caused by division by zero. 

//C#: Exception Handling
//Author:
rajeshvs@msn.com
using System;
class MyClient
{
           public static void Main()
           {
                       int x = 0;
                       int div = 0;
                       try
                       {
                                   div = 100/x;
                                   Console.WriteLine(“This line in not executed”);
                       }
                       catch(DivideByZeroException de)
                       {
                                   Console.WriteLine("Exception occured");
                                  
                      }
                       Console.WriteLine("Result is {0}",div);
           }
}

In the above case the program do not terminate unexpectedly. Instead the program control passes from the point where exception occurred inside the try block to the catch blocks. If it finds any suitable catch block, executes the statements inside that catch and continues with the normal execution of the program statements.

If a finally block is present, the code inside the finally block will get also be executed.  

//C#: Exception Handling
//Author:
rajeshvs@msn.com
  using System;
class MyClient
{
           public static void Main()
           {
                       int x = 0;
                       int div = 0;
                       try
                       {
                                   div = 100/x;
                                   Console.WriteLine("Not executed line");
                       }
                       catch(DivideByZeroException de)
                       {
                                   Console.WriteLine("Exception occured");
                       }
                       finally
                       {
                                   Console.WriteLine("Finally Block");
                       }
                       Console.WriteLine("Result is {0}",div);
           }
}

Remember that in C#, the catch block is optional. The following program is perfectly legal in C#.

//C#: Exception Handling
//Author:
rajeshvs@msn.com
using System;
class MyClient
{
           public static void Main()
           {
                       int x = 0;
                       int div = 0;
                       try
                       {
                                   div = 100/x;
                                   Console.WriteLine("Not executed line");
                       }
                       finally
                       {
                                   Console.WriteLine("Finally Block");
                       }
                       Console.WriteLine("Result is {0}",div);
           }
}
 

But in this case, since there is no exception handling catch block, the execution will get terminated. But before the termination of the program statements inside the finally block will get executed. In C#, a try block must be followed by either a catch or finally block 

Multiple Catch Blocks

A try block can throw multiple exceptions, which can handle by using multiple catch blocks. Remember that more specialized catch block should come before a generalized one. Otherwise the compiler will show a compilation error. 

//C#: Exception Handling: Multiple catch
//Author:
rajeshvs@msn.com
using System;
class MyClient
{
           public static void Main()
           {
                       int x = 0;
                       int div = 0;
                       try
                       {
                                   div = 100/x;
                                   Console.WriteLine("Not executed line");
                       }
                       catch(DivideByZeroException de)
                       {
                                   Console.WriteLine("DivideByZeroException" );
                       }
                       catch(Exception ee)
                       {
                                   Console.WriteLine("Exception" );
                       }
                       finally
                       {
                                   Console.WriteLine("Finally Block");
                       }
                       Console.WriteLine("Result is {0}",div);
           }
}
 

Catching all Exceptions

By providing a catch block without a brackets or arguments, we can catch all exceptions occurred inside a try block. Even we can use a catch block with an Exception type parameter to catch all exceptions happened inside the try block since in C#, all exceptions are directly or indirectly inherited from the Exception class.  

//C#: Exception Handling: Handling all exceptions
//Author:
rajeshvs@msn.com
using System;
class MyClient
{
           public static void Main()
           {
                       int x = 0;
                       int div = 0;
                       try
                       {
                                   div = 100/x;
                                   Console.WriteLine("Not executed line");
                       }
                       catch
                       {
                                   Console.WriteLine("oException" );
                       }
                       Console.WriteLine("Result is {0}",div);
           }
}
 

The following program handles all exception with Exception object.

//C#: Exception Handling: Handling all exceptions
//Author:
rajeshvs@msn.com
using System;
class MyClient
{
           public static void Main()
           {
                       int x = 0;
                       int div = 0;
                       try
                       {
                                   div = 100/x;
                                   Console.WriteLine("Not executed line");
                       }
                       catch(Exception e)
                       {
                                   Console.WriteLine("oException" );
                       }
                       Console.WriteLine("Result is {0}",div);
           }
}

Throwing an Exception

In C#, it is possible to throw an exception programmatically. The ‘throw’ keyword is used for this purpose. The general form of throwing an exception is as follows.

throw exception_obj; 

For example the following statement throw an ArgumentException explicitly.

throw new ArgumentException(“Exception”); 

//C#: Exception Handling:
//Author:
rajeshvs@msn.com
using System;
class MyClient
{
           public static void Main()
           {
                       try
                       {
                                   throw new DivideByZeroException("Invalid Division");
                       }
                       catch(DivideByZeroException e)
                       {
                                   Console.WriteLine("Exception" );
                       }
                       Console.WriteLine("LAST STATEMENT");
           }
}
 

Re-throwing an Exception

The exceptions, which we caught inside a catch block, can re-throw to a higher context by using the keyword throw inside the catch block. The following program shows how to do this.  

//C#: Exception Handling: Handling all exceptions
//Author:
rajeshvs@msn.com
using System;
class MyClass
{
           public void Method()
           {
                       try
                       {
                                   int x = 0;
                                   int sum = 100/x;
                       }
                       catch(DivideByZeroException e)
                       {
                                   throw;
                       }
           }
}
class MyClient
{
           public static void Main()
           {
                       MyClass mc = new MyClass();
                       try
                       {
                                   mc.Method();
                       }
                       catch(Exception e)
                       {
                                   Console.WriteLine("Exception caught here" );
                       }
                       Console.WriteLine("LAST STATEMENT");
           }
}
 

Standard Exceptions
 
There are two types of exceptions: exceptions generated by an executing program and exceptions generated by the common language runtime. System.Exception is the base class for all exceptions in C#. Several exception classes inherit from this class including ApplicationException and SystemException. These two classes form the basis for most other runtime exceptions. Other exceptions that derive directly from System.Exception include IOException, WebException etc. 

The common language runtime throws SystemException. The ApplicationException is thrown by a user program rather than the runtime. The SystemException includes the ExecutionEngineException, StaclOverFlowException etc. It is not recommended that we catch SystemExceptions nor is it good programming practice to throw SystemExceptions in our applications.

System.OutOfMemoryException

System.NullReferenceException

System.InvalidCastException

System.ArrayTypeMismatchException

System.IndexOutOfRangeException        

System.ArithmeticException

System.DevideByZeroException

System.OverFlowException

User-defined Exceptions

In C#, it is possible to create our own exception class. But Exception must be the ultimate base class for all exceptions in C#. So the user-defined exception classes must inherit from either Exception class or one of its standard derived classes.

//C#: Exception Handling: User defined exceptions
//Author:
rajeshvs@msn.com
using System;
class MyException : Exception
{
           public MyException(string str)
           {
                       Console.WriteLine("User defined exception");
           }
}
class MyClient
{
           public static void Main()
           {
                       try
                       {
                                   throw new MyException("RAJESH");
                       }
                       catch(Exception e)
                       {
                                   Console.WriteLine("Exception caught here" + e.ToString());
                       }
                       Console.WriteLine("LAST STATEMENT");
           }
}

Design Guidelines

Exceptions should be used to communicate exceptional conditions. Don’t use them to communicate events that are expected, such as reaching the end of a file. If there’s a good predefined exception in the System namespace that describes the exception condition-one that will make sense to the users of the class-use that one rather than defining a new exception class, and put specific information in the message.

Finally, if code catches an exception that it isn’t going to handle, consider whether it should wrap that exception with additional information before re-throwing it.

"C#" 카테고리의 다른 글
  • Introduction to Objects and Classes in C# (0)2007/07/27
  • Creational Patterns in C# (0)2007/07/27
  • Exception Handling in C# (0)2007/07/27
  • C# 키워드 목록 (0)2007/07/02
  • Event Handling in .NET Using C# (0)2007/06/26
2007/07/27 09:14 2007/07/27 09:14
Posted by webdizen
Tags C#, exception, Handing
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3097

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Network Programming2007/07/27 09:11

Network Programming in C#

출처 : http://www.devarticles.com/c/a/c-sharp/ ··· sharp%2F

Network Programming in C#
(Page 1 of 2 )

Rajesh will now educate C# programmers by demonstrating the correct method of using the Socket class. A must read for those network programmers out there.

The .NET framework provides two namespaces, System.Net and System.Net.Sockets for network programming. The classes and methods of these namespaces help us to write programs, which can communicate across the network. The communication can be either connection oriented or connectionless. They can also be either stream oriented or data-gram based. The most widely used protocol TCP is used for stream-based communication and UDP is used for data-grams based applications. 

The System.Net.Sockets.Socket is an important class from the System.Net.Sockets namespace. A Socket instance has a local and a remote end-point associated with it. The local end-point contains the connection information for the current socket instance. 

There are some other helper classes like IPEndPoint, IPADdress, SocketException etc, which we can use for Network programming. The .NET framework supports both synchronous and asynchronous communication between the client and server. There are different methods supporting for these two types of communication.

A synchronous method is operating in blocking mode, in which the method waits until the operation is complete before it returns. But an asynchronous method is operating in non-blocking mode, where it returns immediately, possibly before the operation has completed.

Dns Class

The System.net namespace provides this class, which can be used to creates and send queries to obtain information about the host server from the Internet Domain Name Service (DNS). Remember that in order to access DNS, the machine executing the query must be connected to a network. If the query is executed on a machine, that does not have access to a domain name server, a System.Net.SocketException is thrown. All the members of this class are static in nature. The important methods of this class are given below. 

public static IPHostEntry GetHostByAddress(string address)

Where address should be in a dotted-quad format like "202.87.40.193". This method returns an IPHostEntry instance containing the host information. If DNS server is not available, the method returns a SocketException. 

public static string GetHostName()

This method returns the DNS host name of the local machine.

In my machine Dns.GetHostName() returns vrajesh which is the DNS name of my machine. 

public static IPHostEntry Resolve(string hostname)

This method resolves a DNS host name or IP address to a IPHostEntry instance. The host name should be in a dotted-quad format like 127.0.01 or www.microsoft.com. 

IPHostEntry Class

This is a container class for Internet host address information. This class makes no thread safety guarantees. The following are the important members of this class. 

AddressList Property

Gives an IPAddress array containing IP addresses that resolve to the host name. 

Aliases Property

Gives a string array containing DNS name that resolves to the IP addresses in AddressList property. 

The following program shows the application of the above two classes.

using System;
using System.Net;
using System.Net.Sockets;
class MyClient
{
           public static void Main()
           {
                       IPHostEntry IPHost = Dns.Resolve("www.hotmail.com");
                       Console.WriteLine(IPHost.HostName);
                       string []aliases = IPHost.Aliases;
                       Console.WriteLine(aliases.Length);
                       IPAddress[] addr = IPHost.AddressList;
                       Console.WriteLine(addr.Length);
                       for(int i= 0; i < addr.Length ; i++)
                       {
                                   Console.WriteLine(addr[i]);
                       }
           }
}

IPEndPoint Class

This class is a concrete derived class of the abstract class EndPoint. The IPEndPoint class represents a network end point as an IP address and a port number. There is couple of useful constructors in this class: 

IPEndPoint(long addresses, int port)
IPEndPoint (IPAddress addr, int port) 
IPHostEntry IPHost = Dns.Resolve("www.c-sharpcorner.com");
Console.WriteLine(IPHost.HostName);
string []aliases = IPHost.Aliases;
IPAddress[] addr = IPHost.AddressList;
Console.WriteLine(addr[0]);
EndPoint ep = new IPEndPoint(addr[0],80);


Network Programming in C# - Part 2
(Page 2 of 2 )

Socket Programming: Synchronous Clients 

The steps for creating a simple synchronous client are as follows.

  1. Create a Socket instance.
  2. Connect the above socket instance to an end-point.
  3. Send or Receive information.
  4. Shutdown the socket
  5. Close the socket 

The Socket class provides a constructor for creating a Socket instance. 

public Socket (AddressFamily af, ProtocolType pt, SocketType st)

Where AddressFamily, ProtocolType and SocketTYpe are the enumeration types declared inside the Socket class.

The AddressFamily member specifies the addressing scheme that a socket instance must use to resolve an address. For example AddressFamily.InterNetwork indicates that an IP version 4 addresses is expected when a socket connects to an end point. 

The SocketType parameter specifies the socket type of the current instance. For example SocketType.Stream indicates a connection-oriented stream and SocketType.Dgram indicates a connectionless stream.

The ProtocolType parameter specifies the ptotocol to be used for the communication. For example ProtocolType.Tcp indicates that the protocol used is TCP and ProtocolType.Udp indicates that the protocol using is UDP. 

public Connect (EndPoint ep)

The Connect() method is used by the local end-point to connect to the remote end-point. This method is used only in the client side. Once the connection has been established the Send() and Receive() methods can be used for sending and receiving the data across the network. 

The Connected property defined inside the class Socket can be used for checking the connection. We can use the Connected property of the Socket class to know whether the current Socket instance is connected or not. A property value of true indicates that the current Socket instance is connected.

IPHostEntry IPHost = Dns.Resolve("www.c-sharpcorner.com");
Console.WriteLine(IPHost.HostName);
string []aliases = IPHost.Aliases;
IPAddress[] addr = IPHost.AddressList;
Console.WriteLine(addr[0]);
EndPoint ep = new IPEndPoint(addr[0],80);
Socket sock = new                             
Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
sock.Connect(ep);
if(sock.Connected)
Console.WriteLine("OK");

The Send() method of the socket class can be used to send data to a connected remote socket.

public int Send (byte[] buffer, int size, SocketFlags flags)

Where byte[] parameter storing the data to send to the socket, size parameter containing the number of bytes to send across the network. The SocketFlags parameter can be a bitwise combination of any one of the following values defined in the System.Net.Sockets.SocketFlags enumerator.
        
SocketFlags.None
SocketFlags.DontRoute
SocketFlags.OutOfBnd
 

The method Send() returns a System.Int32 containing the number of bytes send.Remember that there are other overloaded versions of Send() method as follows. 

public int Send (byte[] buffer,  SocketFlags flags)
public int Send (byte[] buffer)
public int Send (byte[] buffer,int offset, int size, SocketFlags flags)
 

The Receive() method can be used to receive data from a socket.        

public int Receive(byte[] buffer, int size, SocketFlags flags) 

Where byte[] parameter storing the data to send to the socket, size parameter containing the number of bytes to send across the network. The SocketFlags parameter can be a bitwise combination of any one of the following values defined in the System.Net.Sockets.SocketFlags enumerator explained above. 

The overloaded versions of Receive() methods are shown below. 

public int Receive (byte[] buffer,  SocketFlags flags)
public int Receive (byte[] buffer)
public int Receive (byte[] buffer,int offset, int size, SocketFlags flags)
 

When the communication across the sockets is over, the connection between the sockets can be terminated by invoking the method ShutDown() 

public void ShutDown(SocketShutdown how)

Where ‘how’ is one of the values defined in the SocketSHutdown enumeration. The value SoketShutdown.Send means that the socket on the other end of the connection is notified that the current instance would not send any more data.

The value SoketShutdown.Receive means that the socket on the other end of the connection is notified that the current instance will not receive any more data and the value SoketShutdown.Both means that both the action are not possible. 

Remember that the ShutDown() method must be called before the Close(0 method to ensure that all pending data is sent or received. 

A socket can be closed by invoking the method Close(). 

public void Close()

This method closes the current instance and releases all managed and un-managed resources allocated by the current instance. This method internally calls the Dispose() method with an argument of ‘true’ value, which frees both managed and un-managed resources used by the current instance. 

protected virtual void Dispose(bool)

The above method closes the current instance and releases the un-managed resources allocated by the current instance and exceptionally release the managed resources also. An argument value of ‘true’ releases both managed and un-managed resources and a value of ‘false’ releases only un-managed resources. 

The source code for a simple synchronous client by using the sockets is show below. The following program can send an HTTP request to a web server and can read the response from the web server. 

using System;
using System.Net;
using System.Net.Sockets;
using System.Text; 
class MyClient
{
           public static void Main()
           {
                       IPHostEntry IPHost = Dns.Resolve("
www.google.com
");
                       Console.WriteLine(IPHost.HostName);
                       string []aliases = IPHost.Aliases; 
                       IPAddress[] addr = IPHost.AddressList;
                       Console.WriteLine(addr[0]);
                       EndPoint ep = new IPEndPoint(addr[0],80); 
  Socket sock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
                       sock.Connect(ep);
                       if(sock.Connected)
                        Console.WriteLine("OK");
                       Encoding ASCII = Encoding.ASCII;
                       string Get = "GET / HTTP/1.1\r\nHost: " + "www. google.com" +
                       "\r\nConnection: Close\r\n\r\n";
                       Byte[] ByteGet = ASCII.GetBytes(Get);
                       Byte[] RecvBytes = new Byte[256];
                       sock.Send(ByteGet, ByteGet.Length, 0);
                       Int32 bytes = sock.Receive(RecvBytes, RecvBytes.Length, 0);
                       Console.WriteLine(bytes);
                       String strRetPage = null;
                       strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);
                       while (bytes > 0)
                       {
                                   bytes = sock.Receive(RecvBytes, RecvBytes.Length, 0);
                                   strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes);
                                   Console.WriteLine(strRetPage );
                       }
                       sock.ShutDown(SocketShutdown.Both);
                       sock.Close();
           }
}

"Network Programming" 카테고리의 다른 글
  • Socket Programming in C# (0)2007/07/27
  • Network Programming in C# (0)2007/07/27
  • IOCP Thread Pooling in C# (0)2007/07/26
  • UDP 프로그래밍의 기초 (0)2007/05/14
  • ICMP 프로그래밍 (0)2007/05/14
2007/07/27 09:11 2007/07/27 09:11
Posted by webdizen
Tags C#, Network, Socket
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3096

Leave your greetings.

[로그인][오픈아이디란?]

Programming/Network Programming2007/07/26 14:07

IOCP Thread Pooling in C#

출처 : http://www.devarticles.com/c/a/C-Sharp/IOCP-Thread-Pooling-in-C-sharp-Part-I/

IOCP Thread Pooling in C# - Part I
(Page 1 of 3 )

This is the first part of William's two part series on thread pooling in C#. By importing a dll file for IOCP thread support.

When building server based applications in C#, it is important to have the ability to create thread pools.  Thread pools allow our server to queue and perform work in the most efficient and scalable way possible.  Without thread pooling we are left with two options. 

The first option is to perform all of the work on a single thread.  The second option is to spawn a thread every time some piece of work needs to be done.  For this article, work is defined as an event that requires the processing of code.  Work may or may not be associated with data, and it is our job to process all of the work our server receives in the most efficient and fastest way possible.

As a general rule, if you can accomplish all of the work required with a single thread, then only use a single thread.   Having multiple threads performing work at the same time does not necessarily mean our application is getting more work done, or getting work done faster. This is true for many reasons. 

For example, if you spawn multiple threads which attempt to access the same resource bound to a synchronization object, like a monitor object, these threads will serialize and fall in line waiting for the resource to become available.  As each thread tries to access the resource, it has the potential to block, and wait for the thread that owns the resource to release the resource. 

At that point, these waiting threads are put to sleep, and not getting any work done.  In fact, these waiting threads have caused more work for the operating system to perform.  Now the operating system must task another thread to perform work, and then determine which thread, waiting for the resource, may access the resource next, once it becomes available. 

If the threads that need to perform work are sleeping, because they are waiting for the resource to become available, we have actually created a performance problem.  In this case it would be more efficient to queue up this work and have a single thread process the queue. 

Threads that start waiting for a resource before other threads, are not guaranteed to be given the resource first.  In diagram A, thread 1 requests access to the resource before thread 2, and thread 2 requests access to the resource before thread 3.  The operating system however decides to give the resource to thread 1 first, then thread 3, and then thread 2.  This scenario causes work to be performed in an undetermined order.  The possible issues are endless when dealing with multi-threaded applications.


If work received can be performed independent of each other, we could always spawn a thread for processing that piece of work.  The problem here is that an operating system like Windows has severe performance problems when a large number of threads are created or running at the same time, waiting to have access to the CPU. 

The Windows operating system needs to manage all of these threads, and compared to the UNIX operating system, it just doesn’t hold up.  If large amounts of work are issued to the server, this model will most likely cause the Windows operating system to become overloaded.  System performance will degrade drastically.
<>

This article is a case study comparing thread performance between Windows NT and Solaris.

http://www.usenix.org/publications/libr ··· tta.html

In the .NET framework, the “System.Threading” namespace has a ThreadPool class.  Unfortunately, it is a static class and therefore our server can only have a single thread pool.  This isn’t the only issue.  The ThreadPool class does not allow us to set the concurrency level of the thread pool. 

The concurrency level is the most important setting when configuring a thread pool.  The concurrency level defines how many threads in the pool may be in an “active state” at the same time.  If we set this parameter correctly, we will have the most efficient, performance enhanced thread pool for the work being processed.

Imagine we have a thread pool with 4 threads and a concurrency level of 1. Then, three pieces of work are queued up for processing in the pool. Since the concurrency level for the thread pool is 1, only a single thread from the pool is activated and given work from the queue.  Even though there are two pieces of work queued up, no other threads are activated.  This is because the concurrency level is set to 1.  If the concurrency level was set to 2, then another thread would have been activated immediately and given work from the queue.  In diagram B we have thread 1 running and all of the other threads sleeping with two pieces of work queued.

So the question exists, why have more than 1 thread in the pool if the concurrency level is set to 1?  If thread 1 in diagram B ever goes to sleep before it completes its work, another thread from the pool will be activated.  When thread 1 goes to sleep, there are 0 threads “active” in the pool and it is ok to activate a new thread based on the concurrency level.  In diagram C, we now have thread 1 sleeping and thread 4 running with one piece of work queued.

Eventually, thread 1 will wake up, and it is possible for thread 4 to still be active.  We have 2 threads active in the pool, even though the concurrency level is set to 1.  In diagram D, we now have thread 1 and thread 4 running and one piece of work still queued.

The last piece of work in the queue will need to wait until both threads return to a sleeping state.  This is because the concurrency level is set to 1.  As we can see, even though the concurrency level restricts the number of active threads in the pool at any given time, we could have more active threads then the concurrency level allows.  It all depends on the state of the threads in the pool and how fast the threads can complete the work they are processing.

A good rule of thumb is to set the concurrency level to match the number of CPU’s in the system.  If the machine our server is running on only has one CPU, then only one thread can be executing at any given time. It will require a task swap to have another thread get CPU time.  We want to reduce the number of active threads at any given time to maximize performance.  This also leads to scalability.  As the number of CPU’s increase, we can increase the concurrency level because there is a CPU to execute that thread.  This is a general rule and is always a good starting point for configuring our thread pools.

The bottom line is, if the CPU is available, and there is work to perform, activate a thread.  If the CPU is not available, do not activate a thread.  One other thing, we need to be careful that we don’t cause a situation where the threads in the pool are constantly being put to sleep for long periods of time during the processing of work.  This may cause all of the threads in the pool to constantly be in an active state, defeating the efficiency of the pool and the performance of the server.

The remaining scope of this article will show you how to add IOCP thread pools to your C# server based applications.  How to configure the thread pools for your specific application will not be covered.  It is suggested to use the general rules as discussed.

This Win32 API call is used to create an IOCP thread pool.  The first argument will always be set to INVALID_HANDLE_VALUE, which is 0xFFFFFFFF.  This tells the operating system this IOCP thread pool is not linked to a device.  The second argument will always be set to 0. There is no existing IOCP thread pool because we are creating this for the first time.  The third argument will always be null.  IOCP Thread Pooling in C# - Part I - The Article
(Page 2 of 3 )

System Requirements

A basic understanding of C# is required to follow through the examples and the classes.  Basic concepts of type, properties, threading, synchronization, and delegates are required.

Defining the Problem

IOCP thread support has not been made available to C# developers through the “System.Threading” namespace.  We need to access the Win32 API calls from the Kernel32.dll.  This requires us to write unsafe code.  This is really not a problem, but something that needs to be discussed.  Let’s take a look at the Win32 API calls we need to implement an IOCP thread pool.

[DllImport("Kernel32", CharSet=CharSet.Auto)]
private unsafe static extern UInt32 CreateIoCompletionPort(UInt32 hFile, UInt32 hExistingCompletionPort, UInt32* puiCompletionKey, UInt32 uiNumberOfConcurrentThreads);

We do not require a key because we have not associated this IOCP thread pool with a device.  The last argument is the important argument.  Here we define the concurrency level of the thread pool.  If we pass a 0 for this argument the operating system will set the concurrency level to match the number of CPU’s in the machine. 

This option gives us our best chance to be scalable and take advantage of the number of CPU’s present in the machine.  This API call will return a handle to the newly created IOCP thread pool.  If the API call fails, it will return null.

[DllImport("Kernel32", CharSet=CharSet.Auto)]
private unsafe static extern Boolean CloseHandle(UInt32 hObject);

This Win32 API call is used to close our thread pool.  The only argument is the handle to the IOCP thread pool.  This API call will return TRUE or FALSE if the handle can not be closed.

[DllImport("Kernel32", CharSet=CharSet.Auto)]
private unsafe static extern Boolean PostQueuedCompletionStatus(UInt32 hCompletionPort, UInt32 uiSizeOfArgument, UInt32* puiUserArg, OVERLAPPED* pOverlapped);

This Win32 API call is used to post work in the IOCP thread pool queue. Other threads in our application will make this Win32 API call.  The first argument is the handle to the IOCP thread pool.  The second argument is the size of the data we are posting to the queue.  The third argument is a value or a reference to an object or data structure we are posting to the queue.  The last argument will always be null. The following diagram shows how the data is associated with the posted work.

In diagram E, we have two threads actively processing posted work and one piece of work on the queue waiting for its data to be processed.  The thing to note here is that each piece of work was given a reference to its specific data.  I am calling this variable pData to help describe what is happening in the IOCP thread pool.  The actual name or structure of this variable is undocumented.

When we make this API call in a C++ application, we can pass the address of any object in memory we wish, as in diagram E.  In C#, we don’t have the same luxury because of the managed heap.  The managed heap is a contiguous region of address space that contains all of the memory allocated for reference variables.  The heap maintains a pointer that indicates where the next object is to be allocated, and all allocations are contiguous from that point.  This is much different from the C-runtime heap. 

The C-runtime heap uses a link list of data structures to reference available memory blocks.  For the C-runtime heap to allocate memory, it must walk through the link list until a large enough block of free memory is found.  Then the free block of memory must be resized, and the link list adjusted. 

If objects are allocated consecutively in a C++ application, those objects could be allocated anywhere on the heap.  This can never happen with the managed heap.  Objects that are allocated consecutively in a C# application will always be allocated consecutively on the managed heap.  The catch is that the managed heap must be compacted to guarantee the heap does not run out of memory.  That is the job of garbage collection.

For more information on garbage collection, try these links:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconautomaticmemorymanagement.asp

http://msdn.microsoft.com/msdnmag/issues/1100/GCI/default.aspx

http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/default.aspx

In diagram F, we have allocated four objects on the managed heap.  Imagine that the managed heap has allocated memory for these objects at address FDEO, FDDO, FDCO, and FDBO.  This would mean the value of pClass1 is FDEO, the value of pClass2 is FDDO, the value of pClass3 is FDCO, and the value of pClass4 is FDBO. 

MyClass pClass1 = new MyClass();
MyClass pClass2 = new MyClass();
MyClass pClass3 = new MyClass();
MyClass pClass4 = new MyClass();


Now we write the following code.

pClass2 = null;

Diagram G shows what happens to the managed heap after garbage collection takes place and the managed heap is compacted.

The Class 2 object has been removed from the managed heap and the Class3 and Class 4 objects have been moved.  Now the value of pClass3 is FDDO and the value of pClass4 is FDCO.  The value that the pointer points to has changed.  The garbage collection process changes the values of all reference variables to make sure they are pointing to the correct objects after the managed heap is compacted.

So what does this mean for our IOCP thread pool implementation?  If we pass the reference of a managed object as the data for the work, there is a chance the reference is no longer valid when a thread in the pool is chosen to work on the data.

In diagram H, we have passed a reference to the Class 3 object as the data for the work posted to the IOCP thread pool.  This object is at address FDCO.  Before the work is given to thread 1, the Class 2 object is marked for deletion.  Then the garbage collection process runs, and the managed heap is compacted.  Now in diagram I, the work has been given to thread 1 for processing.  The value of pData is still FDCO, but Class 3 is no longer at address FDCO, it is at address FDDO.  The thread will perform the work, but using Class 4 instead of Class 3.

The garbage collection process can not change the value of pData, as it does with other variables, because this variable is not a managed variable.  It is a variable owned by the IOCP thread pool and exists outside the scope of the CLR.  The garbage collector has no knowledge of this variable or access to this variable.  The variable is set during the unsafe call to PostQueuedCompletionStatus.

Unfortunately, pinning the objects we want to pass as the data for the work posted to the IOCP thread pool is not a possible solution.  Pinning provides the ability to prevent an object from being moved on the manage heap during the garbage collection process.  We can not pin these objects because there is no way to pin an object in one thread and unpin the object in a different thread.  To pin an object, we need to use the fixed keyword.  This keyword can only be used in the context of a single method. Here is a quick example of pinning.

Int32 iArray = new Int32[5] {12, 34, 56, 78, 90};
unsafe
{
  fixed (Int32* piArray = iArray)
  {
   // Do Something
  }
}

The safest thing we can do is pass a value to the IOCP thread pool.  This value could be the index from a managed array, containing a reference to an object on the managed heap.   If the garbage collection process does compact the heap, the index values of the array will not change. In diagram J and K, we can see one way to properly pass data for the work posted to the IOCP thread pool.  After the garbage collection process compacts the heap, the values of pData change, but the index positions to the pData variables do not change.

[DllImport("Kernel32", CharSet=CharSet.Auto)]
private static extern Boolean GetQueuedCompletionStatus(UInt32 hCompletionPort, UInt32* pSizeOfArgument, UInt32* puiUserArg, OVERLAPPED** ppOverlapped, UInt32 uiMilliseconds);

The final Win32 API call is used to add threads to the IOCP thread pool. Any thread that makes this Win32 API call will become part of the IOCP thread pool.  This is a blocking call and the method will return when the IOCP thread pool chooses the thread to perform work. 

The first argument is the handle to the IOCP thread pool.  The second argument is the size of the data associated with the work.  This value was provided when the work was posted.  The third argument is the data value or data reference associated with the work.  This value was provided when the work was posted.  The forth argument is the address to a pointer of type OVERLAPPED. 

This address is returned after the call.  The last argument is the time in milliseconds the thread should wait to be activated to perform work. We will always pass INFINITE or 0xFFFFFFFF.

These are the Win32 API calls we need to add IOCP thread pool support to our C# server based applications.  We need to encapsulate these Win32 API calls using .NET threads and minimize the sections of unsafe code.  We need to prevent the application developer from passing a reference variable into the IOCP thread pool, by restricting them to passing only integer values.

IOCP Thread Pooling in C# - Part I - What to Expect in Part 2
(Page 3 of 3 )

In part II of this article, we will build a class that encapsulates a single IOCP thread pool.  The application developer will be able to instantiate as many thread pools as he wishes. 

During construction, the application developer will be able to: set the concurrency level of the thread pool, set the minimum and maximum number of threads in the pool, and will be able to provide a method to be called when work posted to the thread pool needs to be processed. The application developer will also be able to post work with data into the IOCP thread pool.

IOCP Thread Pooling in C# - Part II
(Page 1 of 3 )

In part 2, William will continue to explain how the create a class that will handle threads using a IOCP Thread Pool.

Defining the Solution

We will build a class that encapsulates a single IOCP thread pool.  The application developer will be able to instantiate as many thread pools as he wishes.  During construction, the application developer will be able to: set the concurrency level of the thread pool, set the minimum and maximum number of threads in the pool, and will be able to provide a method to be called when work posted to the thread pool needs to be processed.  The application developer will also be able to post work with data into the IOCP thread pool.

Component Design and Coding

Start by adding a new class to your C# project.  Remove all of the code provided by the Visual Studio .NET wizard.  Then add the following namespaces.  The System.Runtime.InteropServices namespace is required to access the Win32 API methods from the Kernel32 DLL. 

using System;
using System.Threading;
using System.Runtime.InteropServices;

Don’t forget to change the project properties to allow unsafe code blocks. This can be done by opening the project properties and selecting the Configuration Properties.  Under the Build / Code Generation section you will see “Allow unsafe code blocks”.  Set this to true.

Next add the namespace.   You will notice that I have defined a two level namespace.  This is great when you are building a class library with many different classes.

namespace Continuum.Threading
{

The PostQueuedCompletionStatus and GetQueuedCompletionStats Win32 API methods both require a pointer to the Win32 OVERLAPPED structure. Because this structure will be used by the unsafe Win32 API call, we need to make sure the structure is aligned exactly the same way it would be in our C++ applications.  This can be accomplished by using the StructLayout attribute.  By setting the attribute to “LayoutKind.Sequential”, the structure will be aligned based on the same rules as the C++ compiler.

The structure requires members that are pointers.  The only way to add pointers to this structure is to use the unsafe keyword.  We can still use the FCL types when defining the structure.  This is very important because we can make sure the structure is identical to the C++ version.

// Structures
  //==========================================
  /// <summary> This is the WIN32 OVERLAPPED structure </summary>
  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
  public unsafe struct OVERLAPPED
  {
   UInt32* ulpInternal;
   UInt32* ulpInternalHigh;
   Int32   lOffset;
   Int32   lOffsetHigh;
   UInt32  hEvent;
  }

Now it is time to define the IOCP thread pool class.  I am using the keyword sealed in the definition of this class.  The sealed keyword tells the compiler that this class can not be inherited.  If you know there is no reason for a class to be inherited, use the sealed keyword.  Certain run-time optimizations are enabled for the class when the sealed keyword is used.

// Classes
  //============================================
  /// <summary> This class provides the ability to create a thread pool to manage work.  The
  ///           class abstracts the Win32 IOCompletionPort API so it requires the use of
  ///           unmanaged code.  Unfortunately the .NET framework does not provide this functionality </summary>
  public sealed class IOCPThreadPool
  {

The first section of the IOCP thread pool class is the Win32 function prototypes.  These are the same ones described earlier.

  // Win32 Function Prototypes
   /// <summary> Win32Func: Create an IO Completion Port Thread Pool </summary>
   [DllImport("Kernel32", CharSet=CharSet.Auto)]
  private unsafe static extern UInt32 CreateIoCompletionPort(UInt32 hFile, UInt32 hExistingCompletionPort, UInt32* puiCompletionKey, UInt32 uiNumberOfConcurrentThreads);

   /// <summary> Win32Func: Closes an IO Completion Port Thread Pool </summary>
   [DllImport("Kernel32", CharSet=CharSet.Auto)]
   private unsafe static extern Boolean CloseHandle(UInt32 hObject);

   /// <summary> Win32Func: Posts a context based event into an IO Completion Port Thread Pool </summary>
   [DllImport("Kernel32", CharSet=CharSet.Auto)]
  private unsafe static extern Boolean PostQueuedCompletionStatus(UInt32 hCompletionPort, UInt32 uiSizeOfArgument, UInt32* puiUserArg, OVERLAPPED* pOverlapped);

   /// <summary> Win32Func: Waits on a context based event from an IO Completion Port Thread Pool.
   ///           All threads in the pool wait in this Win32 Function </summary>
   [DllImport("Kernel32", CharSet=CharSet.Auto)]
  private unsafe static extern Boolean GetQueuedCompletionStatus(UInt32 hCompletionPort, UInt32* pSizeOfArgument, UInt32* puiUserArg, OVERLAPPED** ppOverlapped, UInt32 uiMilliseconds);

The next section is the constants section.  Here we need to define the Win32 constants required for the Win32 API calls we are going to make later.

// Constants
   /// <summary> SimTypeConst: This represents the Win32 Invalid Handle Value Macro </summary>
   private const UInt32 INVALID_HANDLE_VALUE = 0xffffffff;

   /// <summary> SimTypeConst: This represents the Win32 INFINITE Macro </summary>
   private const UInt32 INIFINITE = 0xffffffff;

   /// <summary> SimTypeConst: This tells the IOCP Function to shutdown </summary>
   private const Int32 SHUTDOWN_IOCPTHREAD = 0x7fffffff;

The delegate function type section is where we define any delegate functions.  We need one delegate function type to define the signature of the function we will call when work needs to be processed.

  // Delegate Function Types
   /// <summary> DelType: This is the type of user function to be supplied for the thread pool </summary>
   public delegate void USER_FUNCTION(Int32 iValue);

These private properties are required to maintain the application developer’s settings.  The most interesting property is the GetUserFunction property.  This property contains a reference to a method supplied by the application developer.  We will use this property to call the application developers method.

  // Private Properties
   private UInt32 m_hHandle;
     /// <summary> SimType: Contains the IO Completion Port Thread Pool handle for this instance </summary>
     private UInt32 GetHandle { get { return m_hHandle; } set { m_hHandle = value; } }

   private Int32 m_uiMaxConcurrency;
     /// <summary> SimType: The maximum number of threads that may be running at the same time </summary>
     private Int32 GetMaxConcurrency { get { return m_uiMaxConcurrency; } set { m_uiMaxConcurrency = value; } }

   private Int32 m_iMinThreadsInPool;
     /// <summary> SimType: The minimal number of threads the thread pool maintains </summary>
     private Int32 GetMinThreadsInPool { get { return m_iMinThreadsInPool; } set { m_iMinThreadsInPool = value; } }

   private Int32 m_iMaxThreadsInPool;
     /// <summary> SimType: The maximum number of threads the thread pool maintains </summary>
     private Int32 GetMaxThreadsInPool { get { return m_iMaxThreadsInPool; } set { m_iMaxThreadsInPool = value; } }

   private Object m_pCriticalSection;
     /// <summary> RefType: A serialization object to protect the class state </summary>
     private Object GetCriticalSection { get { return m_pCriticalSection; } set { m_pCriticalSection = value; } }

   private USER_FUNCTION m_pfnUserFunction;
     /// <summary> DelType: A reference to a user specified function to be call by the thread pool </summary>
     private USER_FUNCTION GetUserFunction { get { return m_pfnUserFunction; } set { m_pfnUserFunction = value; } }
  
   private Boolean m_bDisposeFlag;
     /// <summary> SimType: Flag to indicate if the class is disposing </summary>
     private Boolean IsDisposed { get { return m_bDisposeFlag; } set { m_bDisposeFlag = value; } }
 
These public properties are used to determine if new threads need to be added to the thread pool.  These properties also provide statistical data about the thread pool.  Here we use the Interlocked class to provide serialization when we increment or decrement these properties.  This is the least expensive way to perform serialization.

  // Public Properties
   private Int32 m_iCurThreadsInPool;
     /// <summary> SimType: The current number of threads in the thread pool </summary>
     public Int32 GetCurThreadsInPool { get { return m_iCurThreadsInPool; } set { m_iCurThreadsInPool = value; } }
     /// <summary> SimType: Increment current number of threads in the thread pool </summary>
     private Int32 IncCurThreadsInPool() { return Interlocked.Increment(ref m_iCurThreadsInPool); }
     /// <summary> SimType: Decrement current number of threads in the thread pool </summary>
     private Int32 DecCurThreadsInPool() { return Interlocked.Decrement(ref m_iCurThreadsInPool); }
   private Int32 m_iActThreadsInPool;
     /// <summary> SimType: The current number of active threads in the thread pool </summary>
     public Int32 GetActThreadsInPool { get { return m_iActThreadsInPool; } set { m_iActThreadsInPool = value; } }
     /// <summary> SimType: Increment current number of active threads in the thread pool </summary>
     private Int32 IncActThreadsInPool() { return Interlocked.Increment(ref m_iActThreadsInPool); }
     /// <summary> SimType: Decrement current number of active threads in the thread pool </summary>
     private Int32 DecActThreadsInPool() { return Interlocked.Decrement(ref m_iActThreadsInPool); }
   private Int32 m_iCurWorkInPool;
     /// <summary> SimType: The current number of Work posted in the thread pool </summary>
     public Int32 GetCurWorkInPool { get { return m_iCurWorkInPool; } set { m_iCurWorkInPool = value; } }
     /// <summary> SimType: Increment current number of Work posted in the thread pool </summary>
     private Int32 IncCurWorkInPool() { return Interlocked.Increment(ref m_iCurWorkInPool); }
     /// <summary> SimType: Decrement current number of Work posted in the thread pool </summary>
     private Int32 DecCurWorkInPool() { return Interlocked.Decrement(ref m_iCurWorkInPool); }

The constructor method does several things.  The class state is initialized and then the IOCP thread pool is created with a call to the CreateIoCompletionPort method.  Notice the method call is within the scope of the unsafe keyword.  This is required because we are passing pointers into the Win32 API call. 

The last thing we do is create the minimal number of threads specified by the application developer.  Notice we use the .NET threading classes to create the threads.  We do not need to use the unsafe CreateThread method.  One might think we need to because these threads will be calling the GetQueuedCompletionStatus Win32 API method.

   // Constructor, Finalize, and Dispose
   //***********************************************
   /// <summary> Constructor </summary>
   /// <param name = "iMaxConcurrency"> SimType: Max number of running threads allowed </param>
   /// <param name = "iMinThreadsInPool"> SimType: Min number of threads in the pool </param>
   /// <param name = "iMaxThreadsInPool"> SimType: Max number of threads in the pool </param>
   /// <param name = "pfnUserFunction"> DelType: Reference to a function to call to perform work </param>
   /// <exception cref = "Exception"> Unhandled Exception </exception>
  public IOCPThreadPool(Int32 iMaxConcurrency, Int32 iMinThreadsInPool, Int32 iMaxThreadsInPool, USER_FUNCTION pfnUserFunction)
   {
     try
     {
       // Set initial class state
       GetMaxConcurrency   = iMaxConcurrency;
       GetMinThreadsInPool = iMinThreadsInPool;
       GetMaxThreadsInPool = iMaxThreadsInPool;
       GetUserFunction     = pfnUserFunction;
       // Init the thread counters
       GetCurThreadsInPool = 0;
       GetActThreadsInPool = 0;
       GetCurWorkInPool    = 0;
       // Initialize the Monitor Object
       GetCriticalSection = new Object();
       // Set the disposing flag to false
       IsDisposed = false;
       unsafe
       {
         // Create an IO Completion Port for Thread Pool use
         GetHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, null, (UInt32) GetMaxConcurrency);
       }
       // Test to make sure the IO Completion Port was created
       if (GetHandle == 0)
         throw new Exception("Unable To Create IO Completion Port");
       // Allocate and start the Minimum number of threads specified
       Int32 iStartingCount = GetCurThreadsInPool;
       ThreadStart tsThread = new ThreadStart(IOCPFunction);
       for (Int32 iThread = 0; iThread < GetMinThreadsInPool; ++iThread)
       {
         // Create a thread and start it
         Thread thThread = new Thread(tsThread);
         thThread.Name = "IOCP " + thThread.GetHashCode();
         thThread.Start();
         // Increment the thread pool count
         IncCurThreadsInPool();
       }
     }
     catch
     {
       throw new Exception("Unhandled Exception");
     }
   }

The finalize method is only required to guarantee the IOCP thread pool handle is closed.  As a general rule, if a class allocates a resource outside the scope of the .NET framework, a finalize method is required else do not add a finalize method.  A finalize method will cause the garbage collection process to spend more time trying to release the memory for the object.

   //***********************************************
   /// <summary> Finalize called by the GC </summary>
   ~IOCPThreadPool()
   {
     if (!IsDisposed)
       Dispose();
   }

The dispose method will not return until all of the threads in the pool have been terminated.  We can’t use the Abort method to kill the threads in the pool because any thread blocked, via the call to the GetQueuedCompletionStatus Win32 API method, will not respond to the Abort message. 

The GetQueuedCompletionStatus Win32 API method will cause the thread to run outside the scope of the CLR and the .NET framework will lose access to the thread.  So what we do is post work into the IOCP thread pool.  We pass the SHUTDOWN_IOCPTHREAD data when we post the work.  This will tell the thread to terminate.  Then, we wait in a spin lock, until all of the threads have terminated.  The last thing is to close the IOCP thread pool.

   //**********************************************
   /// <summary> Called when the object will be shutdown.  This
   ///           function will wait for all of the work to be completed
   ///           inside the queue before completing </summary>
   public void Dispose()
   {
     try
     {
       // Flag that we are disposing this object
       IsDisposed = true;
       // Get the current number of threads in the pool
       Int32 iCurThreadsInPool = GetCurThreadsInPool;
       // Shutdown all thread in the pool
       for (Int32 iThread = 0; iThread < iCurThreadsInPool; ++iThread)
       {
         unsafe
         {
           bool bret = PostQueuedCompletionStatus(GetHandle, 4, (UInt32*) SHUTDOWN_IOCPTHREAD, null);
         }
       }
       // Wait here until all the threads are gone
       while (GetCurThreadsInPool != 0) Thread.Sleep(100);
       unsafe
       {
         // Close the IOCP Handle
         CloseHandle(GetHandle);
       }
     }
     catch
     {
     }
   }

The only private method is the IOCPFunction method.  This method is spawned as a thread and is made part of the IOCP thread pool by calling the GetQueuedCompletionStatus Win32 API method.  When the GetQueuedCompletionStatus Win32 API method returns, we check to make sure we are not being asked to shutdown the thread.  The third argument is the data associated with the posted work.  If the data is not SHUTDOWN_IOCPTHREAD, then real work has been posted into the IOCP thread pool and this thread has been chosen to process the work. 

The application developer’s supplied user function is called since the application developer is the only one who knows what needs to be done. Once that is complete, the method checks if a new thread should be added to the pool.  This is done by reviewing the number of active threads in the pool.

   // Private Methods
   //*******************************************
   /// <summary> IOCP Worker Function that calls the specified user function </summary>
   private void IOCPFunction()
   {
     UInt32 uiNumberOfBytes;
     Int32  iValue;
     try
     {
       while (true)
       {
         unsafe
         {
           OVERLAPPED* pOv;
           // Wait for an event
           GetQueuedCompletionStatus(GetHandle, &uiNumberOfBytes, (UInt32*) &iValue, &pOv, INIFINITE);
         }
         // Decrement the number of events in queue
         DecCurWorkInPool();
         // Was this thread told to shutdown
         if (iValue == SHUTDOWN_IOCPTHREAD)
           break;
         // Increment the number of active threads
         IncActThreadsInPool();
         try
         {
           // Call the user function
           GetUserFunction(iValue);
         }
         catch
         {
         }
         // Get a lock
         Monitor.Enter(GetCriticalSection);
         try
         {
           // If we have less than max threads currently in the pool
           if (GetCurThreadsInPool < GetMaxThreadsInPool)
           {
             // Should we add a new thread to the pool
             if (GetActThreadsInPool == GetCurThreadsInPool)
             {
               if (IsDisposed == false)
               {
                 // Create a thread and start it
                 ThreadStart tsThread = new ThreadStart(IOCPFunction);
                 Thread thThread = new Thread(tsThread);
                 thThread.Name = "IOCP " + thThread.GetHashCode();
                 thThread.Start();
                 // Increment the thread pool count
                 IncCurThreadsInPool();
               }
             }
           }
         }
         catch
         {
         }
         // Relase the lock
         Monitor.Exit(GetCriticalSection);
        // Increment the number of active threads
         DecActThreadsInPool();
       }
     }
     catch
     {
     }
     // Decrement the thread pool count
     DecCurThreadsInPool();
   }

The last two public methods are the PostEvent methods.  The first method takes an integer as an argument and the second version takes no argument at all.  The integer is the data the application developer wishes to pass with the work posted into the IOCP thread pool.  In the PostQueuedCompletionStatus Win32 API call, we can see that the third argument is where we pass the data value.   Since this value is always an integer we set the size of the data to four, as seen in the second argument.  Like in the IOCPFunction, we check to see if we need to add a new thread to the pool.

   // Public Methods
   //******************************************
   /// <summary> IOCP Worker Function that calls the specified user function </summary>
   /// <param name="iValue"> SimType: A value to be passed with the event </param>
   /// <exception cref = "Exception"> Unhandled Exception </exception>
   public void PostEvent(Int32 iValue)
   {
     try
     {
       // Only add work if we are not disposing
       if (IsDisposed == false)
       {
         unsafe
         {
           // Post an event into the IOCP Thread Pool
           PostQueuedCompletionStatus(GetHandle, 4, (UInt32*) iValue, null);
         }
         // Increment the number of item of work
         IncCurWorkInPool();
         // Get a lock
         Monitor.Enter(GetCriticalSection);
         try
         {
           // If we have less than max threads currently in the pool
           if (GetCurThreadsInPool < GetMaxThreadsInPool)
           {
             // Should we add a new thread to the pool
             if (GetActThreadsInPool == GetCurThreadsInPool)
             {
               if (IsDisposed == false)
               {
                 // Create a thread and start it
                 ThreadStart tsThread = new ThreadStart(IOCPFunction);
                 Thread thThread = new Thread(tsThread);
                 thThread.Name = "IOCP " + thThread.GetHashCode();
                 thThread.Start();
                 // Increment the thread pool count
                 IncCurThreadsInPool();
               }
             }
           }
         }
         catch
         {
         }
         // Release the lock
         Monitor.Exit(GetCriticalSection);
       }
     }
     catch (Exception e)
     {
       throw e;
     }
     catch
     {
       throw new Exception("Unhandled Exception");
     }
   } 
   //*****************************************
   /// <summary> IOCP Worker Function that calls the specified user function </summary>
   /// <exception cref = "Exception"> Unhandled Exception </exception>
   public void PostEvent()
   {
     try
     {
       // Only add work if we are not disposing
       if (IsDisposed == false)
       {
         unsafe
         {
           // Post an event into the IOCP Thread Pool
           PostQueuedCompletionStatus(GetHandle, 0, null, null);
         }
         // Increment the number of item of work
         IncCurWorkInPool();
         // Get a lock
         Monitor.Enter(GetCriticalSection);
         try
         {
           // If we have less than max threads currently in the pool
           if (GetCurThreadsInPool < GetMaxThreadsInPool)
           {
             // Should we add a new thread to the pool
             if (GetActThreadsInPool == GetCurThreadsInPool)
             {
               if (IsDisposed == false)
               {
                 // Create a thread and start it
                 ThreadStart tsThread = new ThreadStart(IOCPFunction);
                 Thread thThread = new Thread(tsThread);
                 thThread.Name = "IOCP " + thThread.GetHashCode();
                 thThread.Start();
                 // Increment the thread pool count
                 IncCurThreadsInPool();
               }
             }
           }
         }
         catch
         {
         }
         // Release the lock
         Monitor.Exit(GetCriticalSection);
       }
     }
     catch (Exception e)
     {
       throw e;
     }
     catch
     {
       throw new Exception("Unhandled Exception");
     }
   }
  }
}

We have now completed the implementation of the IOCP thread pool class.  Now it is time to test it.

IOCP Thread Pooling in C# - Part II - The Sample Application
(Page 2 of 3 )

Start by adding a new class to your C# project.  Remove all of the code provided by the Visual Studio .NET wizard.  Then add all of the following code.  In Main, an IOCP thread pool is created, and a single piece of work is posted to the IOCP thread pool.  We pass the data value of 10 along with the posted work. 

The main thread is then put to sleep. This gives the IOCP thread function time to wake up to process the work posted.  The last thing in main is to dispose the IOCP thread pool.  The IOCP thread function displays the value of the data passed into the IOCP thread pool.

using System;
using System.Threading;  // Included for the Thread.Sleep call
using Continuum.Threading;
namespace Sample
{
  //============================================
  /// <summary> Sample class for the threading class </summary>
  public class UtilThreadingSample
  {
   //*******************************************
   /// <summary> Test Method </summary>
   static void Main()
   {
     // Create the MSSQL IOCP Thread Pool
     IOCPThreadPool pThreadPool = new IOCPThreadPool(0, 5, 10, new IOCPThreadPool.USER_FUNCTION(IOCPThreadFunction));
     pThreadPool.PostEvent(10);
     Thread.Sleep(100);
     pThreadPool.Dispose();
   }
   //*****************************************
   /// <summary> Function to be called by the IOCP thread pool.  Called when
   ///           a command is posted for processing by the SocketManager </summary>
   /// <param name="iValue"> The value provided by the thread posting the event </param>
   static public void IOCPThreadFunction(Int32 iValue)
   {
     try
     {
       Console.WriteLine("Value: {0}", iValue);
     }
     catch (Exception pException)
     {
       Console.WriteLine(pException.Message);
     }
   }
  }
}

This is what you should see when you run the sample application.  On your own change the main function to call the PostEvent method several times and see how the IOCP thread pool performs.


"Network Programming" 카테고리의 다른 글
  • Socket Programming in C# (0)2007/07/27
  • Network Programming in C# (0)2007/07/27
  • IOCP Thread Pooling in C# (0)2007/07/26
  • UDP 프로그래밍의 기초 (0)2007/05/14
  • ICMP 프로그래밍 (0)2007/05/14
2007/07/26 14:07 2007/07/26 14:07
Posted by webdizen
Tags C#, IOCP, Pooling, Thread
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3095

Leave your greetings.

[로그인][오픈아이디란?]

Programming/C#2007/07/02 22:09

C# 키워드 목록

출처 : C# and the .NET Platform (Second Edition) - Andrew Troelsen, 장시형 역

C# 키워드 설명
bool, byte, char, float, uint, ulong, ushort, decimal, int, sbyte, short, void, double, long, string, object 이 C# 키워드들은 System 네임스페이스에 있는 구조체들에 대한 별칭으로서, CTS의 핵심 데이터 형식을 나타낸다(서명되지 않은 형식은 CLS를 준수하지 않는다).
null 'null' 키워드는 null 참조를 나타내는 리터럴이다.
true, false 이 키워드들은 System.Boolean 형식에 할당될 수 있는 값들을 나타낸다.
out, ref, params 이 키워드들은 형식 멤버로 전달되는 매개변수를 제어하는 데 이용된다.
public, private, internal, protected 이 키워드들은 형식과 멤버들의 가시성(visibility)을 제어하는 데 이용된다.
class, interface, struct, enum, delegate, event 이 C# 키워드들은 사용자 지정 CTS 형식과 형식 멤버들을 만드는 데 이용된다.
return 이 키워드는 형식 멤버의 반환 값을 지정하는 데 이용된다.
as, is 이 키워드들은 한 형식이 다른 형식과 호환되는지를 런타임에 검사할 때 이용된다.
do, while, foreach, in, for 이 C# 키워드들은 반복 구조를 나타낸다.
if, else, switch, case, default, break 이 C# 키워드들은 반복 구조를 나타낸다.
goto, continue 이 키워드들은 선택 구조와 반복 구조에서 흐름 제어에 이용된다.
try, catch, throw, finally 이 키워드들은 런타임 예외를 처리하는 데 이용된다.
operator, explicit, implicit 이 C# 키워드들은 오버로드된 연산자와 사용자 지정 변환 루틴을 지원하는 형식을 만드는 데 이용된다.
this, base 이 키워드들은 현재 객체나 참조 형식의 기본 클래스를 참조하는 데 이용된다.
abstract, virtual, override 이 C#키워드들은 이용하면 클래스 계층에 다형성을 제공할 수 있다.
namespace 이 키워드는 사용자 지정 형식을 포함하는 사용자 지정 네임스페이스를 정의한다.
using

이 키워드는 두 가지 환경에서 이용될 수 있다.
- 네임스페이스 참조
- 객체 자동 처리(disposal)

new

이 키워드는 두 가지 의미로 사용된다.
- 형식 할당
- 상속된 멤버 shadowing

const 이 키워드를 이용하면 상수(즉, 변경할 수 없는) 데이터 포인트를 생성할 수 있다.
checked, unchecked 이 C# 키워드들은 수치 연산과 변환에 대한 오버플로 검사 컨텍스트를 제어하는 데 이용된다.
unsafe, fixed, stackalloc 이 키워드들은 C#으로 메모리 포인터를 이용한 작업에 필요한 안전하지 않은 컨텍스트를 선언하고 사용하는 데 이용된다.
extern 이 키워드는 어떤 멤버가 외부 C 기반 모듈(PInvoke 연산 동안 사용되는)에 정의되어 있다는 것을 나타내는 데 이용된다.
sealed 이 키워드는 확장될 수 없는 클래스 형식을 만드는 데 이용된다.
sizeof 'sizeof' 연산자는 값 형식의 크기를 바이트로 얻어내는 데 이용된다.
volatile 이 키워드는 확장될 수 없는 클래스 형식을 만드는 데 이용된다.
static 이 키워드는 이 키워드가 정의된 형식의 모든 인스턴스에 의해서 공유되는 멤버(또는 데이터 포인트)를 정의하는 데 이용된다.
lock 이 C# 키워드에 대해서는 다중 스레드 프로그래밍을 살펴보면서 알아보게 될 것인데, 스레드로부터 안전한 코드 블록을 표시하는 데 이용된다.
readonly 이 키워드는 선언하면서 또는 동일 클래스의 생성자에서 값이 할당될 수만 있는 필드를 선언한다.
typeof 이 키워드는 System.Reflection을 살펴볼 때 보게 될 것인데, 이 키워드를 이용하면 이 연산자로 전달된 항목에 대한 메타데이터 기술어(descriptor)가 포함된 System.Type 변수를 얻을 수 있다.
"C#" 카테고리의 다른 글
  • Creational Patterns in C# (0)2007/07/27
  • Exception Handling in C# (0)2007/07/27
  • C# 키워드 목록 (0)2007/07/02
  • Event Handling in .NET Using C# (0)2007/06/26
  • C# 명령줄 컴파일러 옵션 (0)2007/05/03
2007/07/02 22:09 2007/07/02 22:09
Posted by webdizen
Tags C#, Keyword, 키워드
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3060

Leave your greetings.

[로그인][오픈아이디란?]

Programming/C#2007/06/26 01:16

Event Handling in .NET Using C#

출처 : http://www.developerfusion.co.uk/show/2137

Introduction

In this article I discuss the event handling model in .NET using C#. The discussion starts with an introduction to the concept of delegates and then it extends that concept to events and event handling in .NET. Finally, I apply these concepts to GUI event handling using windows forms. Complete code is provided in each step of the discussions.

Event handling is familiar to any developer who has programmed graphical user interfaces (GUI). When a user interacts with a GUI control (e.g., clicking a button on a form), one or more methods are executed in response to the above event. Events can also be generated without user interactions. Event handlers are methods in an object that are executed in response to some events occurring in the application. To understand the event handling model of .Net framework, we need to understand the concept of delegate.

Delegates in C#

A delegate in C# allows you to pass methods of one class to objects of other classes that can call those methods. You can pass method m in Class A, wrapped in a delegate, to class B and Class B will be able to call method m in class A. You can pass both static and instance methods. This concept is familiar to C++ developers who have used function pointers to pass functions as parameters to other methods in the same class or in another class. The concept of delegate was introduced in Visulal J++ and then carried over to C#. C# delegates are implemented in .Net framework as a class derived from System.Delegate. Use of delegate involves four steps.

1. Declare a delegate object with a signature that exactly matches the method signature that you are trying to encapsulate.
2. Define all the methods whose signatures match the signature of the delegate object that you have defined in step 1.
3. Create delegate object and plug in the methods that you want to encapsulate.
4. Call the encapsulated methods through the delegate object.

The following C# code shows the above four steps implemented using one delegate and four classes. Your implementation will vary depending on the design of your classes.


Event Handlers in C#

An event handler in C# is a delegate with a special signature, given below.

public delegate void MyEventHandler(object sender, MyEventArgs e);

The first parameter (sender) in the above declaration specifies the object that fired the event. The second parameter (e) of the above declaration holds data that can be used in the event handler. The class MyEventArgs is derived from the class EventArgs. EventArgs is the base class of more specialized classes, like MouseEventArgs, ListChangedEventArgs, etc. For GUI event, you can use objects of these specialized EventArgs classes without creating your own specialized EventArgs classes. However, for non GUI event, you need to create your own specialized EventArgs class to hold your data that you want to pass to the delegate object. You create your specialized EventArgs class by deriving from EventArgs class.

In case of event handler, the delegate object is referenced using the key word event as follows

Now, we will set up two classes to see how this event handling mechanism works in .Net framework. The step 2 in the discussion of delegates requires that we define methods with the exact same signature as that of the delegate declaration. In our example, class A will provide event handlers (methods with the same signature as that of the delegate declaration). It will create the delegate objects (step 3 in the discussion of delegates) and hook up the event handler. Class A will then pass the delegate objects to class B. When an event occurs in Class B, it will execute the event handler method in Class A.



GUI Event Handling

Event handling in Windows Forms (.NET frame work that supports GUI application) employ the .NET event handling model described earlier. We will now apply that model to write a simple application. The application has one class, MyForm, derived from System.Windows.Forms.Form class. Class MyForm is derived from Form class. If you study the code and the three comment lines, you will observe that you do not have to declare the delegates and reference those delegates using event keyword because the events (mouse click, etc.) for the GUI controls (Form, Button, etc.) are already available to you and the delegate is System.EventHandler. However, you still need to define the method, create the delegate object (System.EventHandler) and plug in the method, that you want to fire in response to the event (e.g. a mouse click), into the delegate object.



Conclusion

Other popular object oriented languages like, Java and Smalltalk do not have the concept of delegates. It is new to C# and it derives its root from C++ and J++. I hope that the above discussions will clear this concept to programmers who are starting out C# as their first object oriented language. If you are using Visual Studio IDE for your C# GUI development, attaching your delegate methods to the events generated by GUI controls (like mouse click on a button) can be done without you writing the code. Still, it is better to know what is going on under the hood.

"C#" 카테고리의 다른 글
  • Exception Handling in C# (0)2007/07/27
  • C# 키워드 목록 (0)2007/07/02
  • Event Handling in .NET Using C# (0)2007/06/26
  • C# 명령줄 컴파일러 옵션 (0)2007/05/03
  • C# 스레드 사용 (1)2007/02/05
2007/06/26 01:16 2007/06/26 01:16
Posted by webdizen
Tags C#, Delegate, Event, Handling
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/3057

Leave your greetings.

[로그인][오픈아이디란?]

Programming/C#2007/05/03 13:26

C# 명령줄 컴파일러 옵션

침고 도서: C# and the .NET Plaform (apress)

csc.exe명령줄 플래그
설명
@ 컴파일하는 동안 사용될 지시 파일을 지정하는 데 사용된다.
/? or /help csc.exe의 모든 명령줄 플레그(즉, 이 테이블에 있는 정보)를 보여준다.
/addmodule 다중 어셈블리를 추가할 모듈들을 지정하는 데 사용한다.
/baseaddress *.dll을 로드할 기본 설정 기준 주소를 지정하는 데 사용된다.
/bugreport 해당 컴파일에 대한 텍스트 기반의 버그 리포트를 작성하는 데 사용된다.
/checked 데이터 형식의 범위를 넘어서는(overflow, 오버플로우) 정수 연산이 있을 경우 이 연산으로 인해 런타임에 예외가 발생하는지 여부를 지정하는 데 사용된다.
/codepage 컴파일할 때 모든 소스 코드 파일에 사용할 코드 페이지를 지정하는 데 사용된다.
/debug csc.exe가 디버깅 정보를 내보내게 한다.
/define 전처리기 기호를 정의하는 데 사용된다.
/doc XML 문서 파일을 구성하는 데 사용된다.
/filealign 출력 파일의 섹션 크기를 지정한다.
/fullpaths 컴파일러 출력 파일에 절대 경로를 지정한다.
/incremental 소스 코드 파일의 증분 컴파일을 가능하게 한다.
/lib /reference를 통해 참조하는 어셈블리의 위치를 지정한다.
/linkresource 관리 리소스에 대한 링크를 생성한다.
/main 해당 *.cs 파일들에 여러 개의 Main() 메소드가 정의되어 있는 경우 프로그램의 진입점으로 사용할 Mani() 메소드를 지정한다.
/nologo 파일을 컴파일할 때 컴파일러 배너 정보를 표시하지 않는다.
/nostdlib 핵심 .NET 라이브러리인 mscorlib.dll을 자동적으로 import 하지 않게 한다.
/noconfig 컴파일하는 동안 csc.rep 파일을 사용하지 않게 한다.
/nowarn 지정된 경고를 생성하는 컴파일러 기능을 비활성화한다.
/optimize 최적화를 사용하거나 사용하지 않는다.
/out 출력 파일의 이름을 지정한다.
/recurse 하위 디렉토리에서 컴파일할 소스 파일을 검색한다.
/reference 외부 어셈블리 참조에 사용된다.
/resource 컴파일 결과 생성되는 어셈블리에 .NET 리소스를 포함시킨다.
/targer 출력 파일의 포멧을 지정한다.
/unsafe C#의 'unsafe' 키워드가 사용된 코드를 컴파일한다.
/uft8output UTF-8 인코딩을 사용하여 컴파일러 출력을 표시한다.
/warn 컴파일 시의 경고 수준을 설정하는 데 사용된다.
/warnaserror 경고 수준을 자동적으로 오류로 올리는 데 사용된다.
/win32icon .ico 파일을 출력 파일에 삽입한다.
/win32res Win32 리소스를 출력 파일에 삽입한다.
"C#" 카테고리의 다른 글
  • C# 키워드 목록 (0)2007/07/02
  • Event Handling in .NET Using C# (0)2007/06/26
  • C# 명령줄 컴파일러 옵션 (0)2007/05/03
  • C# 스레드 사용 (1)2007/02/05
  • Office 2003 : Visual Studio Tools for Office Sy... (0)2007/02/05
2007/05/03 13:26 2007/05/03 13:26
Posted by webdizen
Tags C#, 컴파일러 옵션
No Trackback No Comment

Trackback URL : http://www.webdizen.net/blog/trackback/2886

Leave your greetings.

[로그인][오픈아이디란?]

«Prev  1 2  Next»

RSS HanRSS
Blog Image
webdizen
이곳은 컴퓨터에 대해 연구하고, 공유하고, 소통하기 위한 연구실입니다. 개인적으로는 OLAP, Data Mining, Semantic Web, Data Modeling에 대해서 연구하고 있습니다.

Categories

전체 (3009)
Webdizen (141)
Life (6)
Diary (16)
Blog (9)
IDEA (2)
Travel (10)
Book (16)
Photo (7)
Movie (8)
Music (14)
Leisure Sports (10)
Funny (6)
Hardware (121)
Software (120)
Windows (5)
Unix & Linux (120)
Installation (5)
Kernel (10)
System (34)
Develop (22)
X-Window (0)
Applicaton (31)
Security (4)
Framework (2)
Hadoop (2)
Programming (804)
Algorithm & Data Structure (1)
Assembly (38)
UNIX/Linux C (95)
C++ (128)
STL (4)
Java (38)
Win32 API (92)
ATL/COM (44)
MFC (151)
.NET (26)
WCF/WPF (4)
C# (28)
Network Programming (17)
Database Programming (12)
OpenGL / DirectX (13)
Multimedia Programming (0)
Game Programming (21)
Parallel Distributed Progra... (0)
Reverse Engineering (0)
Debugging (9)
Python (1)
Ruby (1)
Ruby on Rails (1)
QT (4)
GTK (0)
JSP (0)
PHP (6)
ASP.NET (6)
ASP (2)
Development (28)
Useful Library (2)
Data Modeling (0)
Database (105)
Oracle (4)
MSSQL (41)
MySQL (2)
Data Warehouse (2)
Data Mining (4)
Network (66)
Web (79)
DHTML (4)
XHTML (1)
Javascript (1)
CSS (1)
AJAX (9)
XML (11)
Flex (1)
Silverlight (3)
Security (91)
DoS (1)
Kernel (10)
Scanning (3)
Sniffing (0)
Spoofing (4)
Overflow (28)
Web (11)
Shell (10)
Format String (14)
Window (2)
Embedded (70)
Multimedia (27)
Mobile (14)
Graphic (24)
Management (633)
Knowledge (581)
Hadoop (0)

Notice

  • 메타 블로그 사이트에 등록
  • 새해 맞이 블로그의 변화
  • 블로그 명칭 변경
  • 도메인(www.webdizen.net) 구...
  • TEXTCUBE 1.6.1로 업그레이드...

Tags

  • 연관 분석
  • GIF
  • 데이타 바인딩
  • 접속 로그
  • 저장소 엔진
  • 연결프로그램
  • 윈도우 소멸
  • Browsing
  • 성능
  • libpcap
  • XP
  • Multi-Rank
  • Child Window
  • 어학교육원
  • 맥주
  • 데이터 마이닝
  • 자연과학대학
  • 파일 시스템
  • 어학원
  • 사용자 로그인 정보

Recent Articles

  • 트위터(Twitter)의 시작!.
  • 청년 리더의 조건.
  • 애플의 타블렛 PC - 아이패드....
  • 미래의 인터페이스 - 육감 기....
  • 기초발성법 동영상 강좌.

Recent Comments

  • 관리자만 볼 수 있는 댓글입....
    비밀방문자 03/12
  • 상대방의 이야기를 열심히 경....
    DoNuts 03/03
  • Lots of students know techn....
    Bobbi35Shannon 02/25
  • 좋은글 잘 보고 갑니다..
    Und_hacker 01/08
  • 재밌네요~ 첫번째꺼는 요즘....
    Hybrid 2009

Recent Trackbacks

  • printf,scanf를 이용한 형식....
    yundream의 프로그래밍 이야기 03/10
  • 파일 열기/저장하기 CFileDialog.
    은마군의 나태블록 2009
  • World IT Show 2008.
    상우 :: Oranzie's BLOG 2008
  • cvs서버 설치하기.
    3인3색 2008
  • 속속 공개되는 Google Chart....
    PHP와 Web 2.0 2007

Archive

  • 2010/02 (1)
  • 2010/01 (6)
  • 2009/12 (5)
  • 2009/09 (3)
  • 2009/08 (1)

Calendar

«   2010/03   »
일 월 화 수 목 금 토
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

Bookmarks

    • Administration
      • IIS.NET
      • NTFAQ
      • OS의 모든 것
      • 리눅스포털
    • Database
      • SQL Server Central
      • SQL Team
    • Development
      • .NET Heaven
      • ASP Alliance
      • ASP.NET 2.0
      • Bullog.net
      • C# Corner
      • C++ (C PlusPlus.com)
      • C++ Reference
      • CodeGuru
      • CodePlex
      • DebugLab
      • Dev Articles
      • Devpia
      • DotNet Junkies
      • DotNet Zone
      • Driver Online
      • GOSU.NET
      • HOONS 닷넷
      • Joinc 팀블로그
      • KOSR
      • MSDN Home Page
      • OSR Online
      • Sky.ph - 개발자 커뮤니...
      • TAEYO.NET
      • The Code Project
      • WindowsClient.net
      • 김상욱의 개발자 Side
      • 조인시 위키
    • Human Networks
      • belief21c's e-space
      • I think I can
      • Invisible Rover's Blog :D
      • Rodman®
      • ■ Feel So Good~! ■
      • 까만 나비
      • 나를 가꾸는 시간.
      • 나만의 즐거움~~!
      • 단녕
      • 상우 :: Oranzie's BLOG
    • Information Technology
      • Microsoft TechNet
      • 지디넷코리아 - 글로벌...
    • Security
      • FoundStone
      • milw0rm
      • NewOrder
      • OpenRCE
      • Phrack.org
      • Reverse Engineering b1...
      • Reverse Engineering Team
      • RootKit
      • SecurityFocus
      • SecurityXploded by Nag...
      • Wow Hacker
      • Zone-H
Textcube
Louice Studio Inc.
Powered by Textcube. Original designed by Tistory.