Delegate ها و Event ها در سی شارپ
در سی شارپ برای برنامه نویسی event driven باید با event ها و delegate ها آشنا بود.
یک نمونۀ این نوع برنامه نویسی ، سیستم even ها در Windows Form ها است. مثلاً یک دکمه را در نظر بگیرید که روی آن کلیک می شود. اگر قبلاً به Event به نام Click که متعلق به دکمه است ، تابعی انتساب داده باشیم، هر موقع که روی آن کلیک می شود، Event Click اجرا می شود و در نتیجه تابع مورد نظر ما اجرا می شود.
delegate
delegate شبیه اشاره گرهای توابع C و C++ هستند. یعنی می توان بوسیلۀ آن به یک تابع اشاره کرد.
بوسیلۀ delegate ها می توان متدهایی که در زمان اجرا (runtime) به آن ها انتساب داده شده اند را اجرا کرد.
یعنی برخلاف فراخوانی توابع معمولی که در زمان کامپایل (compile-time) مشخصند، هر تابع دلخواهی را می توان به آن ها انتساب داد و اجرا کرد.
فراخوانی یک تابع بدون delegate ها
در اکثر موارد قط نیاز است که توابع به صورت معمولی فراخوانی شوند. مثلاً اگر کلاس MyClass تابعی به نام Process داشته باشد، آن را به صورت زیر فراخوانی می کنیم:
کد:
using System;
namespace P30World.NoDelegate
{
public class MyClass
{
public void Process()
{
Console.WriteLine("Process() begin");
Console.WriteLine("Process() end");
}
}
public class Test
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Process();
}
}
}
در اکثر موارد همچین چیزی کفایت می کند. ولی بعضی مواقع لازم است که روشی به کار بریم که بتوانیم این امکان را به استفاده کننده از کلاس بدهیم که خودش معیین کند که چه تبعی باید اجرا شود. این همان سیستم event driven است.
یک delegate ساده
شکل کلی تعریف یک delegate به صورت زیر است:
کد:
delegate result-type identifier ([parameters]);
مثلاً به تعریف نمونۀ زیر دقت کنید:
کد:
public delegate int ButtonClickHandler (object obj1, object obj2)
یک delegate شکل کلی تابعی که قرار است فراخوانی شود را نشان می دهد.
برای استفاده از delegate سه مرحله وجود دارد:
1-تعریف
2-مقداردهی اولیه
3-اجرا
به برنامۀ زیر (SimpleDelegate1.cs) دقت کنید:
کد:
using System;
namespace P30World.BasicDelegate
{
// تعریف
public delegate void SimpleDelegate();
class TestDelegate
{
public static void MyFunc()
{
Console.WriteLine("I was called by delegate ...");
}
public static void Main()
{
// مقداردهی اولیه
SimpleDelegate simpleDelegate = new SimpleDelegate(MyFunc);
// اجرا
simpleDelegate();
}
}
}
که نتیجۀ اجرای آن به صورت زیر است:
کد:
I was called by delegate ...
Event ها
Event های c# به صورت زیر تعریف می شوند.
کد:
public event SimpleDelegate SimpleEvent;
یعنی توابعی از نوع SimpleDelegate را می توان به این Event انتساب داد.
کد:
myClass.SimpleEvent += new SimpleDelegate(myFunc);
و برای اجرای آن:
Event های موجود در .NETFramework خصوصیات زیر را دارند:
* Event Handler های موجود در .NET دو پارامتر می گیرند و void برمی گردانند.
* پارامتر اول شئ را مشخص می کند که event را اجرا کرده.
* پارامتر دوم شئ است که از EventArgs مشتق شده است.
* Event ها باید عضو شئ تامین کندۀ Event باشند. (مثلاً عضو Button)
*
ابتدا به یک برنامۀ ساده دقت کنید:
کد:
using System;
namespace P30World.BasicDelegate
{
// تعریف delegate
public delegate void SimpleDelegate(string sender);
class TestEvent
{
// تعریف Event
public SimpleDelegate SimpleEvent;
public void MyFunc1(string sender)
{
Console.WriteLine("I was called by " + sender + " in MyFunc1");
}
public void MyFunc2(string sender)
{
Console.WriteLine("I was called by " + sender + " in MyFunc2");
}
}
class Program
{
public static void Main()
{
TestEvent test = new TestEvent();
// مقداردهی Event
test.SimpleEvent += new SimpleDelegate(test.MyFunc1);
test.SimpleEvent += new SimpleDelegate(test.MyFunc2);
// اجرای Event
test.SimpleEvent("Main");
}
}
}
که خروجی زیر را می دهد:
کد:
I was called by Main in MyFunc1
I was called by Main in MyFunc2
در این برنامه دو تابع MyFunc1 و MyFunc2 موجودند که آن ها را به SimpleEvent انتساب می دهیم و سپس با اجرای SimpleEvent هر دو با هم اجرا می شوند.
حال به برنامۀ زیر که کمی پیچیده تر است دقت کنید:
کد:
using System;
using System.IO;
namespace P30World.SimpleEvent
{
/* ========= Publisher of the Event ============== */
public class MyClass
{
// Define a delegate named LogHandler, which will encapsulate
// any method that takes a string as the parameter and returns no value
public delegate void LogHandler(string message);
// Define an Event based on the above Delegate
public event LogHandler Log;
// Instead of having the Process() function take a delegate
// as a parameter, we've declared a Log event. Call the Event,
// using the OnXXXX Method, where XXXX is the name of the Event.
public void Process()
{
OnLog("Process() begin");
OnLog("Process() end");
}
// By Default, create an OnXXXX Method, to call the Event
protected void OnLog(string message)
{
if (Log != null)
{
Log(message);
}
}
}
// The FileLogger class merely encapsulates the file I/O
public class FileLogger
{
FileStream fileStream;
StreamWriter streamWriter;
// Constructor
public FileLogger(string filename)
{
fileStream = new FileStream(filename, FileMode.Create);
streamWriter = new StreamWriter(fileStream);
}
// Member Function which is used in the Delegate
public void Logger(string s)
{
streamWriter.WriteLine(s);
}
public void Close()
{
streamWriter.Close();
fileStream.Close();
}
}
/* ========= Subscriber of the Event ============== */
// It's now easier and cleaner to merely add instances
// of the delegate to the event, instead of having to
// manage things ourselves
public class TestApplication
{
static void Logger(string s)
{
Console.WriteLine(s);
}
static void Main(string[] args)
{
FileLogger fl = new FileLogger("process.log");
MyClass myClass = new MyClass();
// Subscribe the Functions Logger and fl.Logger
myClass.Log += new MyClass.LogHandler(Logger);
myClass.Log += new MyClass.LogHandler(fl.Logger);
// The Event will now be triggered in the Process() Method
myClass.Process();
fl.Close();
}
}
}
خروجی برنامه به صورت زیر خواهد بود:
کد:
Process() begin
Process() end
در فایل process.log نیز محتوای زیر قرار می گیرد:
کد:
Process() begin
Process() end
آموزش فارسی ( Persian )
برای اطلاعات بیشتر به اینجا مراجعه کنید:
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]