Showing posts with label C# Tutorial For Beginners. Show all posts
Showing posts with label C# Tutorial For Beginners. Show all posts

Thursday, November 9, 2017

C# For Beginners, Part 45( Difference between String & StringBuilder )

আজকে আমরা , String & StringBuilder নিয়ে কথা বলবো ।। আমরা সাধারণত , এতদিন  String  ব্যবহার করে এসেছি , কিন্তু --- আজ আমরা এটা মূলত মেমোরিতে কাজ করছে ?? সেটা নিয়ে কথা বলবো ।। তার আগে , চলো আমরা নিচের কোড দেখে আসি -------------------


using System;

namespace joy
{
    public class Program
    {
        public static void Main()

        {
            string joy = "c# ";
            joy += "Video ";
            joy += "Tutorial ";
            joy += "for ";
            joy += "beginners";
            Console.WriteLine(joy);
            Console.ReadKey();
        }

    }
   
}

আচ্ছা  এখানে আসলে কি হচ্ছে  ??  আমরা জানি  ,  string একটা ( sealed)  ক্লাস | আমরা যখন , string joy দিয়ে স্ট্রিং ক্লাসের একটা রেফারেন্স ভ্যারিয়েবল ক্রিয়েট করলাম ।। তারপর , সেটা একটা অব্জেক্টকে ( c# )  পয়েন্ট করে ।। তারপর , কনক্যাটিনেশন এর মাধ্যমে , এই  joy রেফারেন্স ভ্যারিয়েবল এর সাথে অন্য একটা অব্জেক্ট  ( Video) ক্রিয়েট করে ,সেটাকে পয়েন্ট করে দিয়েছি ।।
এভাবে , আমরা মোট এখানে পাচটা অব্জেক্ট ক্রিয়েট করেছি । । কিন্তু , কাজের কাজ কিন্তু সেই শেষের অব্জেক্টটাই , প্রথম চারটার কিন্তু আমাদের কোনো দরকার নেই , কিন্তু মেমোরিতে হিপ মেমোরিতে ঠিকই তা রয়ে গেছে , যে পর্যন্ত না গারবেজ কালেক্টর সেগুলোকে ক্লিন না করে । ।


তো , আমাদের এমন একটা ক্লাস  দরকার , যেটা নতুন নতুন অব্জেক্ট ক্রিয়েট না করে - একটা অব্জেক্টকেই পরিবর্তন করবে ।  এ কথাকেই ইংরেজীতে মিউটেবল (  Mutable ) বলা হয় , যার অর্থ পরিবরতনশীল । এর মানে , আমরা বুঝতে পারলাম যে - আমাদের স্ট্রিং অব্জেক্ট'টা  Mutable নয় , এক কথায় বলতে গেলে -  Immutable (  অপরিবরতনশীল ) ।।

তো চলো , আমরা নতুন একটা ক্লাস দেখি ,যেটা - Mutable । এরকম ক্লাস হলো , StringBuilder , চলো দেখে আসি --------------------------

using System;
using System.Text;

namespace joy
{
    public class Program
    {
        public static void Main()

        {
            StringBuilder   joy =new  StringBuilder("c# ");
            joy.Append( "Video ");
            joy .Append( "Tutorial ");
            joy.Append( "for ");
            joy.Append("beginners");
            Console.WriteLine(joy);
            Console.ReadKey();
        }

    }

এখানে , কি হচ্ছে ?? চলো একটু বুঝার ট্রাই করি  ।।   আমাদের এই ক্লাস , হিপ মেমোরিতে - নতুন নতুন করে অব্জেক্ট ক্রিয়েট করছে না ।   আমরা , প্রথমে যে অব্জেক্ট ক্রিয়েট করেছিলাম ( C# )   , সেটাকেই শুধু পরিবরতন করছে  ।।  একেবারে শেষে পরিবর্তন  হয়ে , (c# Video Tutorial for beginners ) হয়ে যায়  ।।  তবে এই ক্ষেত্রে , সিনট্যাক্সগত পরিবর্তনের দিকে আছে , শুধু  Append Method এর ব্যপার । কারণ , এই ক্ষেত্রে আমাদের আগেরটার মতো কনক্যাটিনেশন ইউজ করতে পারবো না ।।। এখানে , আমাদের  Append মেথোড ইউজ করতে হবে । ।

এই মেথোডটা মূলত আগের স্ট্রিং ক্লাসের মতো নতুন ইন্সট্যান্স ক্রিয়েট করে না , এটা একই ইন্সট্যান্স - এ নতুন স্ট্রিং'টা কপি করে চেইঞ্জ করে , যার কারণে শুধু শুধু নতুন নতুন অব্জেক্ট ক্রিয়েট করে না , একই ইন্সট্যান্স এর ভ্যালু বেড়ে যায় ও সাথে সাথে তার ক্যাপাসিটি'ও সময় অনুযায়ী বেড়ে যায় ।।

তো যাই হোক , তুমি বুঝতেই পারছো যে - এটা কতো গুরুত্বপূরণ ভুমিকা পালন করবে , যখন ---আমরা অনেকগুলো স্ট্রিং ম্যানিপিউলিশেন ইউজ করবো !! নিচের ছবিটা দেখে আরো কিছুটা ক্লিয়ার হবে বিষয়টা , আজ এইটুকুই !!! 




C# For Beginners, Part -44 ( Difference Between ToString() & Convert.ToString() )


আজকে আমরা ছোট্ট করে  Convert.ToString() & ToString() এর মধ্যে কি পারথক্য আছে ?? সেটা নিয়ে কথা বলার ট্রাই করবো ।। তার আগে , আমরা দুইটাই বযবহার করেই ছোট্ট একটা প্রোগ্রাম করে আসি --------------

using System;

 public class Program
    {
        public static void Main()

        {
            int a = 23;
            Console.WriteLine(a.ToString());
            Console.WriteLine(Convert.ToString(a));
            Console.ReadKey();
        }

    }

এখানে , আমরা একটা স্ট্রিং নিয়েছি - সেটাকে স্ট্রিং-এ কনভার্ট করেছি । তবে দুই পদ্ধতিতে !! একবার  ToString() ব্যবহার করে , আরেকবার Convert ক্লাসের ToString() মেথোডে ইন্টিজার ভ্যারিয়েবলকে প্যারামিটার হিসেবে পাস করিয়ে ।।  দুই ক্ষেত্রেই , আমরা একই রকম আউটপুট দেখতে পাচ্ছি , আপাতভাবে এর মধ্যে কোনো তফাত মনে হচ্ছে না । কিন্তু এদের ভেতরেও পারথক্য আছে । ।

চলো নিচের কোড দেখে আসি , একটু ---------

using System;

namespace joy
{
    public class Program
    {
        public static void Main()

        {
            int? a = null;
            Console.WriteLine(Convert.ToString(a));
            Console.ReadKey();
        }

    }
}

কোনো , একটা কারণে - মনে করো , আমার ভ্যারিএবলে নাল সেট করা আছে , এখন একে যদি আমি  Convert ক্লাসের ToString() মেথোডে পাঠাই , তাহলে - আমাদের কনভার্টেড স্ট্রিং ও কিন্তু , নাল হবে , তাই না ??? কোনো রকম এক্সসেপশন পাবা না ।। কিন্তু , চলো এবার নীচের প্রোগ্রামটা রান করাই !!!

  using System;

  public class Program
    {
        public static void Main()

        {
            int? a = null;
            Console.WriteLine(a.ToString());
            Console.ReadKey();
        }

    }

ঠিকঠাক আউটপুট পেলে !! কোনোরকম এরর হবারও কথা নয় , এখন তোমাদের মনে প্রশ্ন আসার কথা যে - পার্থক্য টা কোথায় ???
এবার চলো , একটা ক্লাসের অব্জেক্ট ক্রিয়েট করে এই একই কাজ করি , দেখি কি হয় ???

using System;

namespace joy
{
    public class Program
    {
        public static void Main()

        {
            Customer a = null;
            Console.WriteLine(Convert.ToString(a));
            Console.ReadKey();
        }

    }
    public class Customer
    {
        public string Name { set; get; }
    }
}

আমরা  শুধু  Convert  ক্লাস ব্যবহার করে ,করেছি ।। কোনোরকম এরর পাবাও না , যদিও তুমি  Customer ক্লাসের রেফারেন্স ভ্যারিয়েবলে  null সেট করেছো । । তো চলো , এবার আমরা আরেকভাবে ব্যবহার করি ------

using System;

namespace joy
{
    public class Program
    {
        public static void Main()

        {
            Customer a = null;
            Console.WriteLine(a.ToString());
            Console.ReadKey();
        }

    }
    public class Customer
    {
        public string Name { set; get; }
    }
}

রান করিয়ে দেখো , কি হয় ?? আশা করি এরর পাবা !! নীচের মতো ------



 সুতরাং বুঝতেই পারছো , এবার পার্থক্য কোথায় ??? যেখানে , Convert.ToString() নাল হ্যান্ডল করতে পারে , সেখানে -  ToString() সেটা হ্যান্ডল করতে পারে না ,null reference exception পাবা  ।। এটাই এদের ভেতরে মূল পার্থক্য  !! তবে যখন তুমি একটা ক্লাসের রেফারেন্স ভ্যারিয়েবল ক্রিয়েট করবে , ঠিক তখনই এরকম হবে , এটা মাথায় রেখো , তাছাড়া দুইটা একইরকম আচরণ করবে কিন্তু ।।

C# For Beginners , Part -43 ( Overriding Equals() Method )

আজকে  আমরা  Equals() মেথোড  নিয়ে  কথা  বলবো  ।।  ধরো , আমরা দুইটা সংখ্যার চেক করে দেখবো সমান কি না  ??  যদি  সমান  হয়  ,  তাহলে  আউটপুট-এ  True আর না হলে  আউটপুট-এ  False | এই বিষয়টিই , আমরা এনাম দিয়ে করে আসি , তাহলে ওটাও প্র্যাকটিস হয়ে গেলো একটু ------------

using System;

using System.Collections.Generic;

namespace joy
{
    public class Program
    {
        public static void Main()
        {
            Direction d1 = Direction.East;
            Direction d2 = Direction.West;

            Console.WriteLine(d1 == d2);
            Console.WriteLine(d1.Equals(d2));
           
            Console.ReadKey();
        }
    }
    public enum Direction

    {

        East=1,
        West=2
      
    }
}

আচ্ছা আমরা একটা এনাম ক্রিয়েট করেছি , যার ইলিমেন্ট দুইটা ।। তারপর , তাদের মান চেক করেছি , যদি সমান হয় তাহলে  True আর না হলে  False দেখাবে ।। এখানে আমরা আউটপুটের জনয দুইটা পদ্ধতি ইউজ করেছি , একটা  d1 == d2 , আরেকটা   d1.Equals(d2) ।।  তো দুইটাতেই আমাদের একই আউটপুট দেখাচ্ছে , খুবই ভালো কথা - কিন্তু আমরা এই দুইটার মধ্যে পার্থক্য বুঝতে পারছি না ।। তো চলো , আরেকটু এগিয়ে যাই , তাহলে আসতে  আসতে  সব বুঝতে পারবো ।। নতুন আরেকটা কোড দেখি ------------------

using System;

using System.Collections.Generic;

namespace joy
{
    public class Program
    {
        public static void Main()
        {
            Customer C1 = new Customer();
            C1.FirstName = "Nayeem";
            C1.LastName = "Shahriar";
            Customer C2 = C1;
            Console.WriteLine(C2==C1);
            Console.WriteLine(C2.Equals(C1));
           
            Console.ReadKey();
        }
    }
    public class Customer
    {
        public string FirstName { set; get; }
        public string LastName { set; get; }
      
    }
}

এখানে আমরা কি করলাম ?? একটা ক্লাসই ক্রিয়েট করে ফেললাম  । ।   তারপর মেইন মেথোড-এ একই ক্লাসের দুইটি রেফারেন্স ভ্যারিয়েবল   (   C1 ও  C2 ) ক্রিয়েট করলাম , কিন্তু আমাদের কিন্তু এটা মাথায় রাখতে হবে এই দুইটা রেফারেন্স ভ্যারিয়েবলই কিন্তু একটা অব্জেক্টকে পয়েন্ট করছে ।। তাই , আমি যখন রেফারেন্স টাইপ গুলোকে কম্পেয়ার করাই তখন যেহেতু দুইটা রেফারেন্স ভ্যারিয়েবল একই অব্জেক্টকে পয়েন্ট করছে , তাই তাদের সমান ধরে নেয়া হয় , আর তাই আউটপুট  True  আসবে , আর দুইটারই একই অব্জেক্ট পয়েন্ট করা থাকলে , অবশ্যই তাদের মানও সমান হবে ।।

আচ্ছা , এবার আমরা একই ক্লাসের দুইটা রেফারেন্স ভ্যারিয়েবল ক্রিয়েট করবো , সাথে দুইটা অবজেক্টও  ।। চলো দেখি কি হয় ????????????????

using System;

using System.Collections.Generic;

namespace joy
{
    public class Program
    {
        public static void Main()
        {
            Customer C1 = new Customer();
            C1.FirstName = "Nayeem";
            C1.LastName = "Shahriar";
            Customer C2 = new Customer();
            C2.FirstName = "Nayeem";
            C2.LastName = "Shahriar";
            Console.WriteLine(C2==C1);
            Console.WriteLine(C2.Equals(C1));
           
            Console.ReadKey();
        }
    }
    public class Customer
    {
        public string FirstName { set; get; }
        public string LastName { set; get; }
      
    }
}

কোডটি রান করে দেখো , কি আউটপুট আসে ??

এবার কি হলো ?? বলো তো দেখি ?? হুম আমাদের দুই ক্ষেত্রেই একই নাম ব্যবহার করেছি , তারপরো আমাদের এক দেখালো না !! এর কারণ , নিশ্চই বুঝতে পেরেছো ইতিমধ্যে ।। আমরা দুই দুইটা আলাদা আলাদা অব্জেক্ট ক্রিয়েট করেছি সাথে সাথে দুই দুইটা আলাদা আলাদা রেফারেন্স ভ্যারিয়েবল  । যখন আমরা , আলাদা আলাদা ভ্যারিয়েবল চেক করাতে গেলাম , তখনই প্রথম ধাক্কাতে হেরে গেলাম , কারণ দুইটা ভ্যারিয়েবলই আলাদা আলাদা অব্জেক্টকে পয়েন্ট করছে ।।  তাই সেখান থেকেই , ধরে নেয়া হয়েছে যে তারা সমান নয় , এই কারণে - আউটপুটে False পেয়েছি ।।

এখন এই সমস্যা থেকে বাচতে , আমাদের সাহায্য করবে আমাদের  Equals() মেথোড ।। তার ডিফল্টভাবে যে ভারচুয়াল মেথোড আছে , তার   উপরে আমরা ওভাররাইড করার সুযোগ আছে ,আমরা এখন এই সুযোগ ব্যবহার করবো ।।

using System;

using System.Collections.Generic;

namespace joy
{
    public class Program
    {
        public static void Main()
        {
            Customer C1 = new Customer();
            C1.FirstName = "Nayeem";
            C1.LastName = "Shahriar";
            Customer C2 = new Customer();
            C2.FirstName = "Nayeem";
            C2.LastName = "Shahriar";
            Console.WriteLine(C2==C1);
            Console.WriteLine(C2.Equals(C1));
           
            Console.ReadKey();
        }
    }
    public class Customer
    {
        public string FirstName { set; get; }
        public string LastName { set; get; }

        public override bool Equals(object obj)
        {
            if(obj==null)
            {
                return false;
            }
            if(!(obj is Customer))
            {
                return false;
            }

            return this.FirstName == ((Customer)obj).FirstName && this.LastName == ((Customer)obj).LastName;
        }
        public override int GetHashCode()
        {
            return this.FirstName.GetHashCode() ^ this.LastName.GetHashCode();
        }
      
    }
}

তো , আমরা ঠিকঠাকভাবেই সেই সুযোগ ব্যবহার করেছি ।। যদি , আমরা Equals মেথোদের মধ্যে  object টাইপে যে পযারামিটার পাঠাবো , সেটা যদি নাল হয় , তাহলে রিটার্ন তো ভুল হবেই । আর , যদি আমাদের প্যারামিটার হয় অন্য কোনো ক্লাসের টাইপের !! তাহলে তো , কখনো ভিন্ন কোনো টাইপের জিনিস কম্পেয়ার করা হয় না , তাই ভুল হবে ।    [ !(obj is Customer) ]

আর তারপর নামগুলো সমান কি না ?? সেটা চেক করে , তারপর রিটারন করবো [ return this.FirstName == ((Customer)obj).FirstName && this.LastName == ((Customer)obj).LastName;]

আর আমাদের ওয়ারনিং এড়ানোর জন্য , আমরা যখন  Equals  মেথোডের ওভাররাইড করবো , তখন -  GetHashCode() মেথোডেরও ওভাররাইড করবো , এই মেথোড এক ধরনের হ্যাশকোড প্রদান করে যা , সাধারণত এক ধরণের নিউমেরিক ভ্যালু যেটা একটা অব্জেক্ট এর আইডেনটিফেকিশেন হিসেবে কাজ করে , এর সাহায্যে আমরা - দুইটি অব্জেক্ট এর ইকুয়ালিটি চেক করতে পারি খুব এফিশিয়েন্ট ভাবে ।। দুইটা অব্জেক্ট  সমান হলে তাদের হ্যাশকোডও সমান হয় , বাট দুইটা হ্যাশকোড সমান হলেই যে সেই অব্জেক্ট দুটো সমান হবে , তা কিন্তু নয় !! দুইটা অসমান অব্জেক্ট এরও হ্যাশকোড সমান হতে পারে !!!

আসলে , আমরা যখন এই ইকুয়াল মেথোড কল করে , দুইটা অব্জেক্ট এর ইকুয়ালিটি চেক করি তখন অটোমেটিকভাবেই .GetHashCode মেথোড কল করে , হ্যাশ কোড বের করে চেক করে , তাই আমরা
ইকুয়াল মেথোড ইউজ করলে , সাথে সাথে  GetHashCode() মেথোডও অভাররাইড করে দেবো , যদিও আপাতভাবে আমাদের কাছে , এই মেথোড এর কোনো কাজ নেই ।।

 এই বিষয়ে পরবরতিতে বিস্তারিত কথা বলবো ,

আজ কে  আর নয় -----------------------

C# For Beginners Part-42 ( Overriding ToString() method )

আজকে আমরা খুব ছোট্ট একটা বিষয় নিয়ে কথা বলবো , সেটা হলো --- ToString() মেথোড নিয়ে      ।।      এটা ইউজ করবো , এবং এই মেথোডকে ওভাররাইড করবো ।।
প্রথমে খুব সহজ একটা প্রোগ্রাম আমরা , এই মেথোড ইউজ করে করবো , নরমাল একটা সংখ্যাকে স্ট্রিং-এ কনভার্ট করে প্রিন্ট করবো , চলো ----


 public class Program
    {
        public static void Main()
        {
            int a = 10;
            Console.WriteLine(a.ToString());
            Console.ReadKey();
        }
    }

এখন আমরা একটা ক্লাস ক্রিয়েট করে , তার প্রোপারটিকে এই মেথোড দিয়ে ইউজ করার ট্রাই করবো , চলো দেখে আসি ।। 
using System;

namespace joy
{
    public class Program
    {
        public static void Main()
        {
            Customer c = new Customer();
            c.FirstName = "Nayeem";
            c.LastName = "Shahriar";
            Console.WriteLine(c.ToString());
            Console.ReadKey();
        }
    }
    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { set; get; }
    }
}

আমরা একটা নেইমস্পেইস এর ভেতরে , দুইটা ক্লাস ক্রিয়েট করেছি , নতুন ক্লাসের দুইটা প্রোপার্টি রয়েছে ।। যেটাকে , আমি সেট করলাম মেইন ফাংশনে -এবং শুধু সেই রেফারেন্স ভ্যারিয়েবল  c কে যদি উল্লেখ করি , তাহলে তোমায় আউটপুট-এ তোমার ক্লাসের   নেইমস্পেইস.ক্লাসনেইম  শো করবে ।। এটা অবাক হবার কিছু নেই , এটা ডট নেট ফ্রেইমওয়ারক থেকে ডিফল্টভাবেই  ToString() নামক ভারচুয়াল মেথোডের ইমপ্লিমেন্টেশন করা আছে , এই কারণে এরকম শো করবে ।। এখন ঘটনা হলো , একটা কথা আমরা জেনে গেছি - আর সেটা হলো ---  ToString() একটা ভারচুয়াল মেথোড ।।

সো , বুঝতেই পারছো যে -- আমরা একটু মুন্সিয়ানা করলেই এই মেথোডকে ওভাররাইড করতে পারি ।। তো চলো , আমরা একটু বুদ্ধি খাটিয়েই আসি ---
using System;

using System.Collections.Generic;

namespace joy
{
    public class Program
    {
        public static void Main()
        {
            Customer c = new Customer();
            c.FirstName = "Nayeem";
            c.LastName = "Shahriar";
            Console.WriteLine(c.ToString());
            Console.ReadKey();
        }
    }
    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { set; get; }

        public override string ToString()
        {
            return this.FirstName +" "+this.LastName ;
        }
    }
}

এখন দেখো , আমরা কিভাবে ??? একটা মেথোডকে ওভাররাইড করলাম ??আমরা সেই রেফারেন্স ভ্যারিয়েবল c কেই ইউজ করেছি  বাট ডিফল্ট এর বদলে নিজে মেথোডকে ওভাররাইড করেছি ।।।  এখন প্রশ্ন হলো ?? শুধু শুধু আমরা ওভাররাইড করতে গেলাম কেনো ?? আর আমাদের Customer নামক ক্লাসের প্রোপারটি দুটিও তো স্ট্রিং-এই দেয়া আছে , তাই নতুন করেই আবার - ToString() মেথোড ইউজ করলাম কেনো ??? আর এই ওভাররাইড ছাড়াও তো আমি দুইটা প্রোপার্টি ইউজ করতে পারবো । চলো এইসব মেথোড আর ওভাররাইড ছাড়াই আমরা দেখে আসি ----

using System;

using System.Collections.Generic;

namespace joy
{
    public class Program
    {
        public static void Main()
        {
            Customer c = new Customer();
            c.FirstName = "Nayeem";
            c.LastName = "Shahriar";
            Console.WriteLine(c.FirstName+ " " +c.LastName);
            Console.ReadKey();
        }
    }
    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { set; get; }

    }
}

তো আমরা দেখতেই পাচ্ছি যে - কত্ত সহজেই আমরা বিষয়টি করতে পারলাম , তাই না ?? তারপরো , আমরা উপরের মতো এতো জটিল করে কেনো করলাম ?? কেনো ওভাররাইডিং করলাম ।।
এখানে , বেশ কিছু বিষয় আছে , আমাদের যদি কখনো প্রয়োজন হয় , সামনে যে --  ToString() মেথোডকে ওভাররাইড করতে হবে ।। তাহলে কিন্তু আমাদের বিষয়টি জানা থাকলো , খুব সহজেই আমরা করতে পারবো ।। এ ছাড়াও , আরো প্রয়োজনীয়তা সামনেই তুমি নিজেই বুঝতে পারবে আশা করি , আজ এইটুকুই ।।


C# For Beginners , Part- 41 ( Generics )

আজকে আমরা , Generics নিয়ে কথা বলবো এবং এর উপকারিতা সম্পর্কে জানার চেষ্টা করবো ।। তো চলো , আমরা প্রথমেই একটা ছোট্ট প্রোগ্রাম লিখে আসি ---------------------------------
using System;

using System.Collections.Generic;

   public class Program
    {
        public static void Main()
        {
            bool expression = Calculator.AreEqual(10, 10);
            if(expression)
            {
                Console.WriteLine("They are equal");
            }
            else
            {
                Console.WriteLine("They are not equal");
            }
            Console.ReadKey();
        }
    }
public class Calculator
{
   public static bool AreEqual(int value1,int value2)
   {
       return value1 == value2;
   }
   
}

আমরা , এমন একটা প্রোগ্রাম বানাতে চাচ্ছি যে -- যেটা দুইটা টাইপভ্যালু সমান ( ইকুয়াল ) কি না ??? সেটা চেক করে বলে দিবে ।। তো , সেই অনুযায়ি - একটা ছোট্ট প্রোগ্রাম লিখে ফেললাম ।। আমরা যদি চাই , আমরা দুইটা ক্যারেক্টার এর কম্পেয়ার করবো , তাহলে কিন্তু , পারবো না । কারন, আমাদের এই  AreEqual মেথোডটা কিন্তু শুধু ইন্টিজার ডেটা-টাইপ এর উপরে কাজ করবে ( Coupled With int DataType )  |

তো ধরো , আমি আমার এই মেথোডকে যেকোনো ডেটা-টাইপের জন্যই কাজ করাতে চাই , তাহলে কি করানো যেতে পারে ?? হুম তখনই , আমরা ডেটাটাইপ ইউজ করার বদলে object কীওয়ারড ইউজ করবো , নিচের মতো করে , চলো একটা প্রোগ্রাম দেখেই আসি -----------

using System;

using System.Collections.Generic;

   public class Program
    {
        public static void Main()
        {
            bool expression = Calculator.AreEqual('A', 'B');
            if(expression)
            {
                Console.WriteLine("They are equal");
            }
            else
            {
                Console.WriteLine("They are not equal");
            }
            Console.ReadKey();
        }
    }
public class Calculator
{
   public static bool AreEqual(object value1,object value2)
   {
       return value1 == value2;
   }
   
}

এবার কি লক্ষ করেছো যে ?? আমরা কোনো টাইপ উল্লেখ করি নি AreEqual মেথোডে শুধু  object কিওয়ারড ইউজ করেছি ।  এই কারনে ,আমরা যেকোনো টাইপের প্যারামিটারকেই পাস করাতে পারবো এই মেথোডে ।। তাহলে , দেখো এখন আমাদের এই মেথোড কিন্তু  reusable , এর মানে - যে কোনো ডেটাটাইপের জন্যই ইউজ করতে পারবো ।। শুধু , নির্দিষ্ট ডেটাটাইপের জন্যই নয় ।

আচ্ছা আসলে , এখানে কি ঘটনা ঘটছে ??? আমরা  object ইউজ করার ফলে , যেকোনো ডেটাটাইপ প্যারামিটার হিসেবে পাস করাতে পারছি । মুলত , আমাদের সব ডেটাটাইপই ( int , double , char , string etc ) ডিরেক্টলি / ইনডিরেক্টলি  object  ক্লাস থেকে , ইনহেরিটেড হয়েছে , তাই - আমরা ডেটাটাইপের বদলে object ইউজ করে যেকোনো টাইপের ভ্যালু দেই না কেনো , সেটা অটোমেটিক ডিটেক্ট হয়ে যায় ।  আমরা যখন এই  AreEqual মেথোডে প্যারামিটার পাস করাই , তখন --- আমাদের নরমাল যে টাইপগুলো ( int , double ,char , string etc...) আছে সেগুলো সবগুলোই ভ্যালু টাইপ , কিন্তু AreEqual মেথোডে  object ( একটা ক্লাস , রেফারেন্স টাইপ )   কিওয়ারড থাকার ফলে সব ভ্যালু টাইপগুলোই রেফারেন্স টাইপে কনভার্ট হয় ।। এই ঘটনাকে boxing বলা হয় ।। শুধু একটা কম্পারিসন এর জন্য ,অযথাই এই বক্সিং এর ঘটনা প্রোগ্রামের পারফরম্যান্স কে ডিগ্রেটেড করে দেয় ।।

এ ছাড়াও , আমরা যেমন দুইটা ন্টিজারকে তুলনা করেছি / দুইটা ক্যারেক্টারকে তুলনা করেছি ।। কিন্তু , আমরা যদি চাই তাহলে দুইটা প্যারামিটারের ভেতর একটা'কে ইন্টিজার হিসেবে আরেকটাকে স্ট্রিং হিসেবেও পাস করাতে পারি ।। তুমি কোনো কম্পাইল এররও পাবা না , ঠিকঠাক বিল্ড হবে ( আউটপুট কিন্তু ঠিকঠাক নাও পেতে পারো , মানে - তুমি যদি ,  10 & "10" কে পাঠাও , প্যারামিটার হিসেবে -তাহলে ইকুয়াল দেখাব্র কথা থাকলেও , ইকুয়াল নাও দেখাতে পারে ) কিন্ত , কোনো এরর পাবা না ।। object টাইপের জন্য , যেকোনো ধরনের প্যারামিটার পাস করাতে পারবা ।। এর থেকে আমরা বুহতে পারলাম , আমাদের
AreEqual  মেথোডটা কিন্তু , স্ট্রংলি-টাইপ থাকলো না !!!


এই সকল সমস্যা থেকে রেহাই পাবার জন্যই য়ামরা মূলত জেনেরিক্স ইউজ করে থাকি -----------তো চলো তার একটা নরমাল কোড দেখে আসি ,

using System;

using System.Collections.Generic;

   public class Program
    {
        public static void Main()
        {
            bool expression = Calculator.AreEqual<int>(1,2);
            if(expression)
            {
                Console.WriteLine("They are equal");
            }
            else
            {
                Console.WriteLine("They are not equal");
            }
            Console.ReadKey();
        }
    }
public class Calculator
{
   public static bool AreEqual<T>(T value1,T value2)
   {
       return value1.Equals(value2);
   }
   
}

তাহলে , এখানে আমরা কি কি করলাম ?? আমরা , দুইটা অ্যাংগেল ব্রাকেট দিয়ে  T ইউজ করেছি , তারপর প্যারামিটার দুইটির আগেও  T ইউজ করেছি ।। এর মানে , আমাদের এই মেথোড এর প্যারামিটার যে কোনো টাইপেরই হতে পারে , শুধু তাই নয় -- প্যারামিটারগুলো সব এক টাইপেরই হতে হবে , এর আগেরবার যেমন একটা স্ট্রিং এবং আরেকটা ইন্টিজার টাইপ ইউজ করেও এরর খাও নি , কিন্তু এইবার কিন্তু - এরর খাবা ।।  Calculator.AreEqual<int>(1,2) এর মাধ্যমে আমরা স্পেসিফাই করে দিয়েছি , আমাদের AreEqual মেথোডের টাইপ  T কোন ধরনের হবে ?? এই ক্ষেত্রে আমাদের মেথোডটা স্ট্রংলি টাইপ থাকে , এ ছাড়াও এখানে কোনো বক্সিং / আনবক্সিং ঘটে না , তাই প্রোগ্রামের পারফরম্যান্স কখনো ডিগ্রেটেড হয় না ।। আমরা কিন্তু শুধু মেথোড জেনেরিক্স ইউজ না করে ক্লাস জেনেরিক্স ইউজ করতে পারতাম , চলো দেখে নেই ------------

using System;

using System.Collections.Generic;

   public class Program
    {
        public static void Main()
        {
            bool expression = Calculator<int>.AreEqual(1,2);
            if(expression)
            {
                Console.WriteLine("They are equal");
            }
            else
            {
                Console.WriteLine("They are not equal");
            }
            Console.ReadKey();
        }
    }
public class Calculator<T>
{
   public static bool AreEqual(T value1,T value2)
   {
       return value1.Equals(value2);
   }
   
}


তো যাই হোক , এটা আমরা কেনো ব্যবহার করছি ??? এটার বেসিক নিয়ে আমাদের আর কোনো সমস্যা থাকার কথা নয় _______________




Thursday, November 2, 2017

C# For Beginners , Part- 40 ( Attributes )

আজকে আমরা Attribute নিয়ে কথা বলবো ।। এটা ব্যবহারের ফলে  ,আমরা প্রোগ্রামের   রানটাইমে অনেক কিছু ইনফমেশন (Declarative Information) পাবো । এই জন্য , Attribute ইউজ করবো আমরা ।। আমরা যদি , একটা প্রোগ্রাম রান করার সময় কম্পাইলার এরর ও ওয়ার্নিং কেও কাস্টোমাইজ করতে চাই , আমাদের ইচ্ছেমতো শো করাতে চাই , তাহলে আমরা Attribute ইউজ করবো ।। চলো , নিচের কোড দেখি -----

using System;

using System.Collections.Generic;

   public class Program
    {
        public static void Main()
        {
            int b = Calculator.add(10, 20);
            int a=Calculator.add(new List<int>() { 10, 20, 30, 67, 78 });
            Console.WriteLine(a);
            Console.ReadKey();
        }
    }
public class Calculator
{
    [Obsolete]
    public static int add(int firstNumber,int SecondNumber)
    {
        return firstNumber+SecondNumber;
    }
    public static int add(List<int>Number)
    {
        int sum = 0;
        for(int i=0;i<Number.Count;i++)
        {
            sum = sum + Number[i];
        }
        return sum;
    }
}

ধরো আমরা দুটি নাম্বার , এর যোগফল বের করার জন্য , একটা Calculator ক্লাসের ভেতরে , একটা মেথোড ক্রিয়েট করেছি ।। কিন্তু , সমস্যা হচ্ছে -- যদি অনেকগুলো নাম্বার এর যোগফল বের করতে হয় , তখন তো এই দুইটি নাম্বার এর যোগফল বের করার মেথোড কোনো কাজেই দেবে না , তাই না ?? তাই আমরা একই নামে - আরো একটি মেথোড ক্রিয়েট করেছি , বাট এবার লিস্ট ব্যবহার করেছি ।। তো যাই হোক , আমরা চাচ্ছি যে --- ইউজার যেনো দুই মেথোডই ব্যবহার করতে পারে । কিন্তু , প্রথম মেথোড ইউজ করলে যেনো ওয়ার্নিং পায় , তো এই জন্য আমরা একটা Attribute ইউজ করেছি , সেটা হলো [Obsolete] , তবে তুমি [ObsoleteAttribute] হিসেবেও লিখতে পারো সমস্যা নেই  ।। তারপর , আমরা মেইন মেথোড-এ দুই মেথোডকেই কল করেছি ।। এবার , int b = Calculator.add(10, 20); এর উপরে মাউস নিয়ে এসো , কি লিখা ওঠে ?? তোমায় কি ওয়ারনিং দেয় ??
আশা করি , বুঝতে পেরেছো যে - এটা কিন্তু আমাদের [Obsolete] অ্যাট্রিবিউট এর জন্যই দিয়ে থাকে , এই ওয়ারনিং ।। এবার আমরা এই   Attribute কে আরো কিছুটা  কাস্টোমাইজ করতে পারি ।। চলো দেখি কিভাবে ??

[Obsolete("Please Don't Use This , Use List<int>Number ")] , এখন Attribute এর  ভেতরে  এই কথাটি লিখেই মাউস টা এখন আবার int b = Calculator.add(10, 20); এর উপর মাউস টা রেখেই দেখো না ?? কি হয় ??
আশা করি , বুঝতে পেরেছো ।।   একটা কথা মনে রাখবো , আমাদের এই Obsolete কিন্তু একটা ক্লাস , যেটা Attribute নামক ক্লাস থেকে ইনহেরিটেড হয়েছে ।।

আচ্ছা , এখন তুমি যদি চাও যে -- কেউ যদি প্রথম মেথোডটি ইউজ করে তাহুলে যেনো , এরর দেখায় - কম্পাইল না হয়।। তাহলে চলো দেখি , কি হয় ???

[Obsolete("Please Don't Use This , Use List<int>Number ",true)], অর্থাৎ তুমি  Obsolete ক্লাসের কন্সট্রাক্টর-এ বুলিয়ান হিসেবেও প্যারামিটার পাস করাতে পারো , true ইউজ করার ফলে - এটা তোমাকে ওয়ারনিং এর বদলে এখন সরাসরি এরর দেখাবে, কম্পাইল হবে না  ।। আর যদি তুমি , false ইউজ করো তাহলে আগের মতোই শুধু ওয়ারনিং দেখাবে - আর কিছু নয় ।।

যাই হোক , আরো কিছু  Attribute নিয়ে আমরা পরে আলোচনা করবো ।। তাহলে আমরা , কম্পাইলার এরর ও ওয়ার্নিং কেও কাস্টোমাইজ করতে পারবো , তাই না ?? শুধু Attribute ইউজ করে   !!

আপাতত এইটুকুই ------------------------








C# For Beginners - Part 39 ( Access Modifiers In Type )

আজকে আমরা টাইপ এর জন্য , অ্যাকসেস মোডিফায়র নিয়ে আলোচনা করবো ।। টাইপ এর ক্ষেত্রে  শুধু   internal & public মোডিফায়রকেই ইউজ করা যায় ।। অন্য কোনো কিছু ইউজ করতে গেলে , কম্পাইল এরর পাবা ।। এটা নতুন করে দেখানোর কিচ্ছু নেই ।।

তুমি যখন পাবলিক মোডিফায়ার ইউজ করবা । তখন তুমি এক অ্যাসেম্বলির একটা টাইপ অন্য একটা অ্যাসেম্বলি থেকেও ওযাকসেস করতে পারবা , কোনো বাধা নেই , তো চলো ভিন্ন দুইটা অ্যাসেম্বলির কোড দেখে আসি ।।

Assembly two এর কোড ----

using System;

namespace AssemblyLibrary2
{
    public class AssemblytwoClass2
    {
        public void joy()
        {
            Console.WriteLine("Joy Vai");
            Console.ReadKey();
        }
      
    }
}

এবার , অ্যাসেম্বলি-১ এর কোড , যেখান থেকে -- অ্যাসেম্বলি -২ এর  AssemblytwoClass2 ক্লাসের মেম্বারগুলো  অ্যাকসেস করার ট্রাই করবো -----

using System;
using AssemblyLibrary2;

namespace Assembly1
{
    public class AssemblyoneClass1
    {
        public void toy()
        {
            AssemblytwoClass2 r = new AssemblytwoClass2();
            r.joy();
        }
    }
}

এখন বিল্ড করলে , দেখবে , কোনো রকম এরর পাবা না ।। এর মানে , পাবলিক মোডিফায়ার এর জন্য - তুমি এক অ্যাসেম্বলি থেকে টাইপগুলোকে অন্য অ্যাসেম্বলি'তে অ্যাকসেস করতে পারবা ।।

এবার চলো ,  internal মোডিফায়ার এর ব্যবহার দেখার ট্রাই করি । । এখানে , সেই টাইপ মেম্বার এর মতোই ঘটনা ঘটে ।। এক অ্যাসেম্বলি'র টাইপ অন্য কোনো অ্যাসেম্বলিতে ইউজ করতে পারবা না , যদি তুমি  internal মোডিফায়ার ইউজ করো ।।

আর একটি বিষয় জেনে রাখা উচিত যে - তোমরা যদি কোনো মোডিফায়ার ইউজ না করো , তাহলে ডিফল্টভাবেই internal হয়ে যায় ।। আশা করি , এ বিষয়ের কনসেপ্ট তোমাদের অনেকটাই ক্লিয়ার হয়ে গেছে ।।




C# For Beginners , Part-38 ( Acces Modifiers In Type Members )



আজকে প্রথমে , আমরা টাইপ মেম্বার এর অ্যাকসেস মোডিফায়ার গুলোর মধ্যে , শুধু তিনটি নিয়ে কথা বলবো ।

Private

Protected

Public


Private -- এই অ্যাকসেস মোডিফায়ার ইউজ করার মানে হলো , আমরা ওই টাইপ মেম্বারকে শুধু ঐ টাইপ (ক্লাস, স্ট্রাক্ট,এনাম , ইত্যাদি ) এর মধ্যেই অ্যাকসেস করতে পারবো , তার বাইরে অন্য কোনো ক্লাসে অথবা , তার ডেরাইভড ক্লাসেও অ্যাকসেস করতে পারবো না ।। শুধুমাত্র ওই টাইপ-এই ইউজ করতে পারবো । ।

Public ---- এই  অ্যাকসেস মোডিফায়ার ইউজ  করলে , তুমি সেই টাইপ মেম্বার কে শুধু ওই টাইপের ভেতরেই নয় , তার বাইরেও - অন্য ক্লাসেও , এমনকি অন্য অ্যাসেম্বলি'তেও ইউজ করতে পারবে ।
( অ্যাসেম্বলি ) নিয়ে পরে কথা বলবো , আপাতত এইটুকু জেনে রাখলেই চলবে ।। পাবলিক অ্যাকসেস মোডিফায়ার একদমই প্রাইভেট এর ঠিক উলটো ।।

Protected--- এই অ্যাকসেস মোডিফায়ার ব্যবহারের ফলে , আমরা সেই টাইপ মেম্বারকে শুধু ওই টাইপে অথবা , ওই টাইপের কোনো ডেরাইভড টাইপে অ্যাকসেস করা যাবে ।। এর বাইরে ইউজ করতে পারবে না তুমি ।। চলো একটা ছোট্ট উদাহরণ দেখে আসি ----------------

using System;
using System.Collections.Generic;


public class joy
{
    protected int id=14 ;
}
public class toy : joy
{
    public  void print()
    {
        Console.WriteLine(id);
    }
}

public class Program
{

    public static void Main()
    {

        toy r = new toy();
        r.print();
        Console.ReadKey();
    }

}
      
   উপরের কোডটা রান করে দেখো ।
  তাহলে আমরা , দেখতেই পেলাম - শুধু ঐ টাইপ-এই নয় , তার বাইরেও -- তার ডেরাইভড ক্লাসেও আমি অ্যাকসেস করতে পারি ।।    
   
 এখন আমরা বাকি দুইটা নিয়ে কথা বলবো ।।  Internal & Protected Internal |


আমরা যখন একটা  শি শার্প প্রোগ্রাম কম্পাইল করাই , তখন তখন অ্যাসেম্বলি ফাইল ক্রিয়েট হয় ( এটা সাধারনত , মেশিন কোড ) , সেটা দুই ধরনের হতে পারে । একটা হলো - এক্সিকিউটেবল ( এর এক্সটেনশন হলো . ( .exe ) [ তুমি যখন , প্রোগ্রাম লিখো - তার ডান পাশেই সলুউশন এক্সপ্লোরারে - সেই প্রোগ্রামের নাম লিখা থাকে যার ভেতরে project কথাটি লিখা থাকে সেখানে ক্লিক করলেই অনেকগুলো অপশন দেখতে পাবে , Open Folder In File Explorer তে ক্লিক করলেই , এই প্রোগ্রামের ফাইল আসে , তাতে ক্লিক করে  bin->Debug গেলেই , তোমার সেই এক্সিকিউটেবল ফাইল ( .exe) দেখতে পাবে ]। এটাই মেশিন কোড ( ইন্টারমিডিয়েট ল্যাংগুয়েজ, যেটা তোমার লিখা সোর্স কোড থেকে ক্রিয়েট হয় ) , যেটা অটোমেটিক জেনারেটেড হয়  ।।

আচ্ছা , এখন এই অ্যাসেম্বলি দুই ধরনের হতে পারে , একটার এক্সটেনশন .exe আরেকটার এক্সটেনশন .dll || তার আগে , আমরা - আমাদের এই প্রোজেক্টের ভেতরে  Add->New Project->Class Library ক্রিয়েট করলাম , আবার । ( খেয়াল রেখ , এটা কিন্তু - কনসল অ্যাপ্লিকেশন  নয় , এটা একটা নতুন ক্লাস লাইব্রেরি ক্রিয়েট করছো - তুমি ) এখন তোমার ফুল প্রোজেক্ট আবার বিল্ড করাও , এখন তোমার খোলা নতুন ক্লাস লাইব্রেরি তে আগের মতো করে Open Folder In File Explorer->bin->Debug তে গেলেই , তোমরা নতুন আরেক ধরনের অ্যাসেম্বলি দেখতে পাবে , যার এক্সটেনশন .dll ।  আচ্ছা , এখন আরো একটা ক্লাস লাইব্রেরি খুলে ফেলো । ।

আচ্ছা , এবার আসি আসল কথায় । । এখন তুমি যে নতুন দুইটা অ্যাসেম্বলি আছে তার  যে কোনো একটাতে   internal অ্যাকসেস মোডিফায়ার ইউজ করে টাইপ মেম্বার ডিক্লেয়ার করো , তাহলে ।  তুমি ওই অ্যাসেম্বলি'র বাইরে সেটা কোনোভাবেই  অ্যাকসেস করতে পারবে না ।।

এবার আসি , Protected Internal এর ব্যাপারে । যদি , তুমি কোনো - একটা অ্যাসেম্বলি'তে একটা ক্লাসে  Protected Internal অ্যাকসেস মোডিফায়ার ইউজ করি , তাহলে সেটা শুধু সেই অ্যাসেম্বলিতেই নয় , অন্য যে কোনো অ্যাসেম্বলি'তে যদি , ওই ক্লাসের ডেরাইভড কোনো ক্লাস ব্যবহার কোনো ক্লাস ব্যবহার করা হয় , তাহলে সেখানে অ্যাকসেস করা যাবে । ।  আশা করি , বিষয়টি অনেকটাই পরিষ্কার হয়ে গেছে ।। এর পরের পর্বে , আমরা আলোচনা করবো - টাইপ এর ক্ষেত্রে অ্যাকসেস মোডিফায়ার এর ব্যবহার নিয়ে ।। তবে এখানে , কিছু ব্যপার আছে ----

তুমি যদি , প্রথম অ্যাসেম্বলি'র ভেতরের ক্লাসে একটা Protected Internal ইউজ করে একটা মেম্বার ডিক্লেয়ার করো ,

using System;
namespace AssemblyLibrary2
{
    public class AssemblytwoClass2
    {
       protected internal int ID = 101;
    }
}

 তারপর সেটা অন্য একটা অ্যাসেম্বলি থেকে ইনহেরিটেন্স ক্লাসের মাধ্যমে অ্যাকসেস করতে চাও , তাহলে তোমায় । সেই অ্যাসেম্বলির রেফারেন্স-এ ক্লিক করে , এই AssemblyLibrary2 কে ইনক্লুড করতে হবে , তারপর using Directory ইউজ করে AssemblyLibrary2 ডিক্লেয়ার করতে হবে , তারপর নিচে দেখো , অন্য অ্যাসেম্বলি এর কোড , যেখান থেকে আমরা  অ্যাকসেস করতে চাচ্ছে ---


using System;
using AssemblyLibrary2;

namespace Assembly1
{
    public class AssemblyoneClass1
    {

    }
   
    public class Joy : AssemblytwoClass2
    {
        public  void print()
        {
            AssemblytwoClass2 r = new AssemblytwoClass2();
            base.ID = 143;
            Joy e = new Joy();
            e.ID = 156;
           
            Console.ReadKey();
        }
    }
}

আমরা  ,প্রথমেই -- সেই AssemblyLibrary2  অ্যাসেম্বলির AssemblytwoClass2 ক্লাস থেকে Joy নামক ক্লাস ডেরাইভড করে নিলাম ।। এখন আমরা , জানি এই Joy ক্লাসটি সেই তার বেইস ক্লাস AssemblytwoClass2 এর সকল মেম্বার অ্যাকসেস করার ক্ষমতা রাখে , সুতরাং আমরা সেটাকে অ্যাকসেসও করলাম , কিন্তু বেইস ক্লাসের অব্জেক্ট ক্রিয়েট করে base অপারেটর ছাড়া আমরা সেটাকে অ্যাকসেস করতে পারবো না , চাইল্ড ক্লাসের অবজেক্ট ক্রিয়েট করে সহজেই অ্যাকসেস করতে পারবো , কারণ - চাইল্ড ক্লাস তার বেইস ক্লাসের সব মেম্বার অ্যাকসেস করার ক্ষমতা রাখে ।। এখন বিল্ড করলে , কোনো এরর দেখাবে না ।।

আশা করি , টাইপ মেম্বার এর ক্ষেত্রে অ্যাকসেস মোডিফায়ার নিয়ে আর কোনো ঝামেলা থাকার কথা নয় ।।





Sunday, October 29, 2017

C# For Beginners , Part-37 ( Types & Type Members )

আজকে আমরা , টাইপ ও টাইপ মেম্বার এর তফাত নিয়ে কথা বলবো ।। চলো , একটা  কোড দেখে আসি ----------

using System;

public class student
{
    public int Passmark
    {
        set;
        get;
    }
    public int ID
    {
        set;
        get;
    }
}
public class Program
{
    public static void Main()
    {
        student c1 = new student();
        c1.ID = 101;
        c1.Passmark = 40;
        Console.WriteLine("Student ID no. {0}", c1.ID);
        Console.WriteLine("Student Passmark {0}", c1.Passmark);
        Console.ReadKey();
    }
}

এখানে আমরা , একটা ক্লাসের ভেতরে তাদের প্রোপার্টি গুলো দেখতে পাচ্ছি ।। একটা ক্লাসে যে প্রোপার্টি থাকে ,কন্সট্রাক্টরগুলো থাকে মেথোডগুলো থাকে , ক্লাস ফিল্ড থাকে তার সবগুলোকেই বলা হয়ে থাকে ,ক্লাস মেম্বার / টাইপ মেম্বার ।।

আর ক্লাস , স্ট্রাকচার , এনাম ,ইন্টারফেইস -এইসবকিছুই হলো টাইপ ,হোক সেটা ভ্যালু টাইপ অথবা রেফারেন্স টাইপ !! এই সবগুলোই হলো টাইপ ।।

আচ্ছা আমাদের এখন জেনে নিতে হবে , আমাদের মোট অ্যাকসেস মোডিফায়ার আছে ৫ টি ।

১) Private
২) Public
৩) Protected
৪) Internal
৫) Protected Internal

একটা টাইপ মেম্বার এর এই সবগুলোই অ্যাকসেস মোডিফায়ার হওয়াই সম্ভব , বাট একটা টাইপ এর শুধু মাত্র ২টা অ্যাকসেস মোডিফায়ার হওয়াই সম্ভব ।। সেই দুইটা হলো , Internal ও  Public ।
আমরা অ্যাকসেস মোডিফায়ার নিয়ে পরে , ডিটেইলস আলোচনা করবো ।

আচ্ছা , আমরা এখন রেজিয়ন নিয়ে একটু কথা বলবো ।। একটা পুরো কোডকে রিজিওনে ভাগ করে আমরা কাজ করতে পারি , চলো উপরের কোডটাই একটু অন্যরকমভাবে দেখে আসি ।।

using System;
using System.Collections.Generic;



public class student
{
#region Passmark Properties
    public int Passmark
    {
        set;
        get;
    }
#endregion Passmark Properties

#region ID Properties
    public int ID
    {
        set;
        get;
    }
#endregion ID Properties
}
public class Program
{
#region Main Method
    public static void Main()
    {
        student c1 = new student();
        c1.ID = 101;
        c1.Passmark = 40;
        Console.WriteLine("Student ID no. {0}", c1.ID);
        Console.WriteLine("Student Passmark {0}", c1.Passmark);
        Console.ReadKey();
    }
#endregion Main Method
}
      
 এখন আমরা প্রত্যেকবার যে রিজিওন লিখেছি , তার বাম পাশে ছোট্ট মাইনাস(-) চিহ্ন আছে , সেখানে ক্লিক করলেই তুমি বুঝতে পারবে , আমি কেনো এটা ইউজ করলাম ।।

যাই হোক আজ আর কথা বাড়াবো না ।। এইটুকুই -----    
   



C# For Beginners , Part-34 ( Multicast Delegate )

আজকে আমরা মাল্টিক্যাস্ট ডেলিগেট নিয়ে আলোচনা করবো ।। ধরো আমরা একটা ডেলিগেট দিয়ে - এক এর অধিক ফাংশনকে পয়েন্ট করবো ।।
চলো আমরা সিম্পল একটা সমস্যা দেখে আসি ---------------------------------------------

using System;
using System.Collections.Generic;

public delegate void SampleDelegate();
    class Program
    {
        public static void Main(string[] args)
        {
            SampleDelegate d1, d2, d3, d4;
            d1 = new SampleDelegate(method1);
            d2 = new SampleDelegate(method2);
            d3 = new SampleDelegate(method3);
            d4 = d1 + d2 + d3;
            d4();
            Console.ReadKey();
        }
        public static void method1()
        {
            Console.WriteLine("It Is Method No.1");
        }

        public static void method2()
        {
            Console.WriteLine("It is Method No.2");
        }

        public static void method3()
        {
            Console.WriteLine("It is Method No.3");
        }
     
    }

 এখানে আমরা  SampleDelegate নামে যে ডেলিগেট ক্রিয়েট করেছি , সেটা - তিনটা মেথোড/ফাংশনকে পয়েন্ট করছে ।। আমরা ,SampleDelegate  এর জন্য  মোট  ৪ টা রেফারেন্স ভ্যারিয়েবল ক্রিয়েট করেছি ।। তারপর , আমরা SampleDelegate নামের ডেলিগেট-এর তিন তিনটা কন্সট্রাক্টরে , আমাদের তিন তিনটা মেথোডের নাম উল্লেখ করে দিয়েছি ।। এরপর , + অপারেটরের মাধ্যমে তিনটাই একসাথে করে , d4 তে অ্যাসাইন করে দিয়েছি ,এর মানে - d4 এর মাধ্যমে আমরা তিনটা মেথোডকেই পয়েন্ট করছি  ।। আর তারপর তো , d4() এর মাধ্যমে তিনটা আউটপুটই দেখাচ্ছি ।। একটা জিনিস খেয়াল রাখা উচিত , আমরা যেভাবে - যে সিরিয়ালে, d4 এ অ্যাসাইন করবো , সেই অনুযায়ি আউটপুট দেখতে পাবো ।। আমি যদি , d4=  d1 + d3 + d2 ; এভাবে লিখতাম তাহলে তুমি মেথোড-১ এর পর মেথোড-৩ আগে দেখতে , তারপর মেথোড-২ ।।

এখন ধরো , তুমি -- মেথোড-২  প্রিন্ট করবে না , তাহলে তুমি কিন্তু  d4=d1+d2+d3-d2 ; এভাবে লিখতে পারো ।। আবার , d4 = d1 + d3 ; এভাবেও লিখতে পারো ।। তোমার ইচ্ছে !!

আবার , তুমি তিনটি মেথোডকেই কল করার জন্য ,আরো একটা উপায় ইউজ করতে পারো , সেটা হলো -----------

            SampleDelegate d;
            d = new SampleDelegate(method1);
            d =d+ method2 + method3;
            d();

এর মানে , তুমি মেথোড-১ এর জন্য যে ডেলিগেট আছে , তার সাথেই - বাকি দুটি মেথোড এর রেজিস্ট্রার করানো ।। আবার তুমি , যদি যে কোনো দুইটি মেথোড রান করাতে চাও , তাহলে এভাবেও করতে পারবে ---------
            SampleDelegate d;
            d = new SampleDelegate(method1);
            d += method3;          
            d();

আচ্ছা ধরো , আমরা তো শুধু ভয়েড টাইপ নিয়েই কাজ করলাম । এখন যদি ফাংশনগুলি ---যদি ভয়েড ছাড়াও অন্যকিছু রিটার্ন করে , তাহলে কি হবে ?? তখন কোনটার'টা আসলে প্রিন্ট হবে ?? চলো দেখে আসি --

using System;
using System.Collections.Generic;

public delegate int SampleDelegate();
    class Program
    {
        public static void Main(string[] args)
        {
            SampleDelegate d;
            d = new SampleDelegate(method1);
            d += method3;
            d += method2;

            int DelegateReturnValue = d();
            Console.WriteLine(DelegateReturnValue);
           
            Console.ReadKey();
        }
        public static int method1()
        {
            return 1;
        }

        public static int method2()
        {
            return 2;
        }

        public static int method3()
        {
            return 3;
        }
     
    }


আচ্ছা , তাহলে -- আমরা তিনটা মেথোডই রেজিস্ট্রার করালাম , প্রথমটার সাথে , এখন দেখি আউটপুট-এ কোনটা'র টা দেখায় ?? রান করে দেখে নাও । হুম , সবসময়ই -- সবশেষে , যেটা অ্যাসাইন করবে সেটারই ভ্যালু দেখাবে , বিষয়টা খুব ভালো করে মাথায় রেখো ।। আউটপুট প্যারামিটারের ক্ষেত্রেও একই রকম ব্যপার হবে , বিষয়টি ,মনে রেখো ----------------

using System;
using System.Collections.Generic;

public delegate void SampleDelegate(out int n);
    class Program
    {
        public static void Main(string[] args)
        {
            SampleDelegate d;
            d = new SampleDelegate(method1);
          
            d += method2;

            int DelegateReturnValue = -1;

            d(out DelegateReturnValue);
            Console.WriteLine(DelegateReturnValue);
           
            Console.ReadKey();
        }
        public static void method1(out int n)
        {
            n= 1;
        }

        public static void method2(out int n)
        {
            n= 2;
        }
    }

 তো যা হোক , এইটুকুই । ডেলিগেট নিয়ে আরো কথা হবে -- পরে ডিতেইলস-এ ।। আপাতত এইটুকুই -----------------------






C# For Beginners, Part-33 ( Delegate )

আজকে আমরা  Delegate নিয়ে কথা বলবো । শুনে ভয় পাবার কিছু নেই , প্রথম প্রথম অন্যরকম লাগলেও , ব্যবহার করতে করতে ঠিক হয়ে যাবে ।। চলো একটা ছোট উদাহরণ দেখে আসি ----

using System;

public delegate void HelloFunction(string message);
    class Program
    {
        public static void Main(string[] args)
        {
            HelloFunction r = new HelloFunction(hello);
            r("Hello Delegate");
        }
        public static void hello(string s)
        {
            Console.WriteLine(s);
            Console.ReadKey();
        }
    }

আমরা একটা Delegate ক্রিয়েট করেছি ।। delegate  কিওয়ারড ইউজ করে । Delegate  অনেকটাই মেথোডের মতোই । অ্যাকসসেস মোডিফায়ার আছে , রিটার্ন টাইপ আছে ।। প্যারামিটার আছে । হুবহু , একটা মেথোডের মতোই , বাট একটা জিনিস একটু অমিল সেটা হলো - এটা মূলত অন্য একটা মেথোডকে পয়েন্ট করে । ঠিক যেমনটা , আমরা একটা ক্লাসের অব্জেক্ট ক্রিয়েট করার সময় যেমন ,
রেফারেন্স ভ্যারিয়েবল ডিক্লেয়ার করি , যেটা ওই ক্লাসের অব্জেক্টকে পয়েন্ট করে , ঠিক প্রায় একইরকম ভাবে এখানে Delegate জিনিসটা ব্যবহার করা হয় , অন্য একটা মেথোড\ফাংশন কে পয়েন্ট করবার জন্য ।। একটা জিনিস মনে রাখা জরুরী যে - আমাদের  Delegate যে মেথোডকে পয়েন্ট করবে , সেই মেথোড এর  Signature এবং আমাদের  Delegate এর  Signature সেইম হতে হবে ।।

আমি  HelloFunction নামে একটা  Delegate ক্রিয়েট করলাম ।। তারপর , HelloFunction r = new HelloFunction(hello) এর মাধ্যমে আমি এই  Delegate এর অব্জেক্ট ক্রিয়েট এর সময়ই এর কন্সট্রাক্টরে hello নামক মেথোডের নাম দিয়েছি ।। মানে , আমাদের এই  Delegate , hello নামক মেথোডকে পয়েন্ট করবে ।। তারপর , "Hello Delegate" নামক স্ট্রিং প্যারামিটার হিসেবে পাঠিয়ে সেটাকে কনসল স্ক্রিনে শো করালাম , hello নামক মেথোড দিয়ে , বাট নেপথ্যে কাজ করে গেলো  , HelloFunction নামক delegate ।। এই জন্য  Delegate কে বলা হয় , Function Pointer |

আচ্ছা আমরা কিন্তু , ওপরের কোড-এ ডেলিগেট ক্রিয়েট না করেও , খুব সহজেই নিচের মতো করে কোড লিখতে পারতাম ।।
using System;

    class Program
    {
        public static void Main(string[] args)
        {

            hello("Hello Delegate");
        }
        public static void hello(string s)
        {
            Console.WriteLine(s);
            Console.ReadKey();
        }
    }

একই আউটপুট পাবো , বাট আমরা ডেলিগেট আসলে কিভাবে ? কাজ করে ? এটা বুঝতে পারবো না ।। তাই , আমি ডেলিগেট ইউজ করেই লিখেছি ।। এই পর্যন্ত , যতো টুকু হলো - সেইটুকুই আমরা আরো ভালোভাবে দেখে নেই , তারপর আমরা বাকি আলোচনায় এগুবো । উপরের টুকু ভালো করে না বুঝে , নিচে এগুনো ঠিক হবে না ।।


এবার আমরা শিখবো - কেনো এর এতো প্রয়োজনীয়তা ????? চলো একটা কোড দেখে আসি -----------------

using System;
using System.Collections.Generic;
   public class Program
    {
        public static void Main(string[] args)
        {

            List<Employee> emplist = new List<Employee>();
            emplist.Add(new Employee() { ID = 110, name = "Joy", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 111, name = "Jony", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 112, name = "Joga", Salary = 30000, Experience = 2 });
            Employee.PromoteEmployee(emplist);
        }
      
    }
public class Employee
{
    public int ID { get; set; }
    public string name { get; set; }
    public int Salary { get; set; }
    public int Experience { get; set; }

    public static void PromoteEmployee(List<Employee>employeelist)
    {
        for(int i=0;i<3;i++)
        {
            if(employeelist[i].Experience>=5)
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }
          
        }
        Console.ReadKey();
    }
}

আমরা , একটা  Employee ক্লাসের ভেতরে - চারটে প্রোপার্টি ক্রিয়েট করেছি ।। একটা মেথোড ক্রিয়েট করে ,প্যারামিটার হিসেবে লিস্ট ইউজ করেছি । যেহেতু , এর আগে লিস্ত নিয়ে কথা বলি নি , তাই একটু নতুন লাগতে পারে , কিন্তু ভয় পাবার কিছু নেই ।। এটা আহামরি কোনো ব্যপার নয় ।। তারপর আমরা , অপর ক্লাসের মেইন মেথোডে গিয়ে -আরো একটা লিস্ট ক্রিয়েট করেছি । যেখানে , প্রোপারটির মান গুলো সেট করে দিয়েছি । তারপর , সেটাকে আমাদের Employee  ক্লাসের ভেতরের মেথোডে প্যারামিটার হিসেবে পাঠিয়েছি ।। আশা করি , কিছুটা ক্লিয়ার হয়েছে ।।

এখন একটা জিনিস খেয়াল করে দেখো যে -- আমরা আমাদের এমপ্লয়িদের জন্য একটা শর্ত বেধে দিয়েছি , যদি অভিজ্ঞতা ৫ বছর / তার চেয়ে বেশী হয় , তাহলে -- তাদের প্রোমোশন হবে , অন্যথায় হবে না , তাই না ?? বাট মনে করো , আমরা শর্ত গুলো চেইঞ্জ করতে চাই ।।তখন কি করতে হবে ??? আমাদের এই এমপ্লয়ি ক্লাসের ভেতরে এসে , সব শর্ত ইত্যাদি চেইঞ্জ করতে হবে । যে কারণে  , এই প্রোগ্রামের ফ্লেক্সিবিলিটি হারাবে ।। তাই যদি , এই ক্লাসে না ঢুকেই বাইরে থেকে আমরা এই ক্রাইটেরিয়াগুলো চেইঞ্জ করতে পারতাম !! তাহলে খুবই ভালো হতো , তাহলে যে কোনো সময় -- আমরা বাইরে থেকেই ইচ্ছে মতো সবকিছু চেইঞ্জ করতে পারতাম ।। তাই না ??? তাহলে আমরা এই একই ক্লাসকে বার বার ইউজ করতে পারবো ।। চলো বড়ো একটা কোড দেখে আসি ----

using System;
using System.Collections.Generic;
    class Program
    {
        public static void Main(string[] args)
        {

            List<Employee> emplist = new List<Employee>();
            emplist.Add(new Employee() { ID = 110, name = "Joy", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 111, name = "Jony", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 112, name = "Joga", Salary = 30000, Experience = 2 });
            IsPromotable isPromotable = new IsPromotable(promote);

            Employee.PromoteEmployee(emplist, isPromotable);
        }
       public static bool promote(Employee emp)
        {
           if(emp.Experience>=5)
           {
               return true;
           }
           else
           {
               return false;
           }
        }
      
    }
 delegate bool IsPromotable(Employee emp);
 class Employee
{
    public int ID { get; set; }
    public string name { get; set; }
    public int Salary { get; set; }
    public int Experience { get; set; }

    public static void PromoteEmployee(List<Employee> employeelist, IsPromotable s)
    {
        for(int i=0;i<3;i++)
        {
            if(s(employeelist[i]))
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }
          
        }
        Console.ReadKey();
    }
}


ভেঙ্গে ভেঙ্গে ,একটু বোঝার ট্রাই করি , আসলে কি হয়েছে ??? প্রথমে আমরা একটা ডেলিগেট  ক্রিয়েট করলাম । [  delegate bool IsPromotable(Employee emp) ]
যার টাইপ হলো , বুলিয়ান আর প্যারামিটার টাইপ হলো এমপ্লয়ী ক্লাস ।। আচ্ছা , যেহেতু আমরা একটা ডেলিগেট ক্রিয়েট করেই ফেললাম , তাই সেইম সিগনেচার-এই আরেকটা মেথোড ক্রিয়েট করতে হবে , যাকে এই ডেলিগেট পয়েন্ট  করবে ।। 

  public static bool promote(Employee emp)
        {
           if(emp.Experience>=5)
           {
               return true;
           }
           else
           {
               return false;
           }
        }

এখানে , আমরা এর ঠিক আগেরবার ডেলিগেট ছাড়া করার সময় যখন ইফ স্টেইট্মেন্ট এর ভেতরে যে শর্ত ইউজ করেছিলাম ।  এখনো , তাই করলাম ।  ।  আচ্ছা , এইবার আমরা
IsPromotable isPromotable = new IsPromotable(promote); ডেলিগেট এর নামে ইন্সটযান্স ক্রিয়েট করার সময় - ডেলিগেট এর কন্সট্রাক্টরে - promote মেথোডের নাম দিলাম ।। এর মানে , ডেলিগেটকে যখনই ডাকা হবে , তখনই ডেলিগেট নিজে কোনো কিছু না করে এই  promote নামক মেথোডকে কল করবে ( পয়েন্ট করবে ) ।

এখন এই ডেলিগেটকে প্যারামিটার হিসেবে  Employee নামক সেকেন্ড ক্লাসের PromoteEmployee নামক মেথোডে প্যারামিটার হিসেবে ,পাঠিয়ে দিলাম । ভয় পাবার কিছু নেই , প্যারামিটার হিসেবে ডেলিগেট পাস করানো যায় । । public static void PromoteEmployee(List<Employee> employeelist, IsPromotable s) এর মাধ্যমে ,  PromoteEmployee মেথোডেও সেই ডেলিগেটকে টেইক করলো ।।  তারপর , ইফ এর ভেতরে শর্তকে - if(s(employeelist[i])) দ্বারা প্রতিস্থাপিত করলাম । ।  আচ্ছা , এবার ইফ এর ভেতরে কি কাজ হচ্ছে ???
চলো হালকা করে ব্যাখ্যা করে নেই ।।
যখন  s(employeelist[i]) লিখা হলো , তখন - আমরা আমাদের ডেলিগেটকে কল করে তার ভেতরে পযারামিটার হিসেবে লিস্ট এর প্রথম এলিমেন্ট দিয়ে দেলাম । ডেলিগেট তখন , সে যে মেথোডকে পয়েন্ট করে , সেই  promote মেথোডকে প্যারামিটার হিসেবে লিস্ট এর প্রথম এলেমেন্ট পাস করে , আর আমাদের মেথোড এই এলিমেন্ট এর  (emp.Experience>=5) Experience নামক প্রোপার্টি চেক করে True / False রিটার্ন করে ।। যেটার ভিত্তিতে ,

 if(s(employeelist[i]))
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }

লাইন এক্সিকিউট হয় ।। আশা করি , কিভাবে ? ডেলিগেট ইউজ করে কাজ করলাম সেটা ক্লিয়ার হয়ে গেছে , অনেকটাই ।।

এখন আমাদের অনেকেই , এতটা কোড লিখতে আলস্য প্রকাশ করে , আমরা কিন্তু উপরের কোডকেই আরো অনেক কম কোদেই লিখতে পারবো ।। চলো দেখে আসি ,
using System;
using System.Collections.Generic;
    class Program
    {
        public static void Main(string[] args)
        {

            List<Employee> emplist = new List<Employee>();
            emplist.Add(new Employee() { ID = 110, name = "Joy", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 111, name = "Jony", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 112, name = "Joga", Salary = 30000, Experience = 2 });
          

            Employee.PromoteEmployee(emplist, emp1=>emp1.Experience>=5);
        }
     
      
    }
 delegate bool IsPromotable(Employee emp);
 class Employee
{
    public int ID { get; set; }
    public string name { get; set; }
    public int Salary { get; set; }
    public int Experience { get; set; }

    public static void PromoteEmployee(List<Employee> employeelist, IsPromotable s)
    {
        for(int i=0;i<3;i++)
        {
            if(s(employeelist[i]))
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }
          
        }
        Console.ReadKey();
    }
}

আমাদের ডেলিগেট এর জন্য আলাদ কোনো মেথোড ক্রিয়েট করতে হলো না ।। Employee.PromoteEmployee(emplist, emp1=>emp1.Experience>=5); খুব সহজেই এক লাইনেই সব কাজ করে দিলাম , তাই না ?? কিন্তু তুমি যদি এর বেসিকটা বুঝতে চাও , কিভাবে কাজ করছে ?? তাহলে তোমায় -- সেই আগের কোডটাই প্র্যাক্টিস করা উচিত ।। তারপর তুমি যখন পুরো বিষয় ক্লিয়ার হয়ে যাবে , তখন না হয় তুমি শর্ট -কাট ইউজ করতে পারবে ।।  emp1=>emp1.Experience>=5 এই এক্সপ্রেশনকে , ল্যামডা এক্সপ্রেশন বলা হয় ।। আচ্ছা , একটা জিনিস মাথায় রেখো - এই ল্যামডা এক্সপ্রেশন দেখতে ছোট হলেও , রানটাইমে কিন্তু -- সেই একই কাজ হচ্ছে । ডিফল্টভাবেই , ডেলিগেট এর অব্জেক্ট ক্রিয়েট হচ্ছে, তারপর ফাংশনে প্যারামিটার পাস হচ্ছে ,সেইম কাজই হচ্ছে  ...ইত্যাদি ।। তো আশা করি , বুঝতে পারলে ডেলিগেট ইউজ করে আমরা আমাদের প্রোগ্রামকে অনেকটাই ফ্লেক্সিবল করতে পারি ।।

Saturday, October 28, 2017

C# For Beginners,Part-36( Why Enums ? Its Importance )

আজকে আমরা , enum নিয়ে আলোচনা করবো ।। এটা কেনো ইউজ করবো ?? কি ভাবে - ইমপ্লিমেন্ট করবো ???
মূলত প্রোগ্রামকে আরো বেশী  readable & maintainable করার জন্যই  enum এর ব্যবহার করা হয় ।।

তার আগে আমরা নরমাল একটি প্রোগ্রাম দেখে নেই ।। চলো ,

using System;
using System.IO;

public class Joy
{
   
    public static void Main()
    {
        Customer[] customers = new Customer[3];
        customers[0] = new Customer
        {
            name = "Mark",
           gender= 1
        };
        customers[1] = new Customer
        {
            name = "Mary",
            gender = 2
        };
        customers[2] = new Customer
        {
            name="Sam",
            gender=3
        };
        for(int i=0;i<3;i++)
        {
            Console.WriteLine("Name ={0} && Gender={1}",customers[i].name,Getgender(customers[i].gender));
        }
        Console.ReadKey();
      
    }
    public static string Getgender(int gender)
    {
        switch(gender)
        {
            case 1:
                return "Male";
                    case 2:
                return "FeMale";
                    case 3:
                return "Unknown";
            default:
                return "Invalid";
        }
    }


    }

public class Customer
{
    public string name { set; get; }
    public int gender { set; get; }
}

এখানে আমরা , Customer নামের একটা ক্লাস ক্রিয়েট করলাম ,এর আবার দুইটা প্রোপারটিও আছে ।।  তারপর - অন্য ক্লাসে গিয়ে আমরা এই ক্লাসের অব্জেক্ট ক্রিয়েট করলাম । আমরা একটা সুইস কেইস ব্যবহারও করেছি ।। পুরো বিষয়টা বুঝতে চাইলে , তোমরা কোড'টি রান করে আগে দেখো ।। ক্লিয়ার হয়ে যাবে ।

যাই হোক এখন , একতা জিনিস এখানে একটু সতর্কতার সাথে লক্ষ করলে দেখা যাবে যে --- আমরা যদি সুইস কেইস এর দিকে না তাকাই , তাহলে কিন্তু - তুমি বুঝতেই পারবে না যে - gender 1 /2 /3
হলে - কি হবে ?? মেইল হবে , নাকি ফিমেইল হবে ? নাকি অন্যকিছু ?? এটা বোঝার জন্য তোমায় কিন্তু - সুইস স্টেইট্মেন্ট এর ভেতরের শর্ত গুলো দেখতে হবে ।। এখন আমি যদি চাই , আমি প্রোগ্রামটাকে আরো
readable & maintainable করতে চাই , যেনো খুব সহজেই আমরা দেখলেই বুঝতে পারি কোনটা কি হবে ?? সেই জন্য ওপরের কোডটাকেই একটু অন্যরকমভাবে লিখবো ,আর সেটা enum ব্যবহার করে । চলো তো , দেখে আসি ...............

using System;
using System.IO;


public class Joy
{
   
    public static void Main()
    {
        Customer[] customers = new Customer[3];
        customers[0] = new Customer
        {
            name = "Mark",
           gender= Gender.Male
        };
        customers[1] = new Customer
        {
            name = "Mary",
            gender = Gender.Female
        };
        customers[2] = new Customer
        {
            name="Sam",
            gender=Gender.Unknown
        };
        for(int i=0;i<3;i++)
        {
            Console.WriteLine("Name ={0} && Gender={1}",customers[i].name,Getgender(customers[i].gender));
        }
        Console.ReadKey();
      
    }
    public static string Getgender(Gender gender)
    {
        switch(gender)
        {
            case Gender.Male:
                return "Male";
                    case Gender.Female:
                return "FeMale";
                    case Gender.Unknown :
                return "Unknown";
            default:
                return "Invalid";
        }
    }


    }

public enum Gender
{
    Male,
    Female,
    Unknown
}

public class Customer
{
    public string name { set; get; }
    public Gender gender { set; get; }
}
  

তাহলে আমরা , উপরের প্রোগ্রামটি রান করে দেখি ।। আশা করি , ভয় কিছুটা কেটে গেছে - এটা নিয়ে ভয় পাবার কিছু নেই ।  যেহেতু  enum বিষয়টি আমাদের কাছে একদমই নতুন , তাই ভয় পাবার কিছু নেই ।।
আমরা , এই  enum কিওয়ারড দিয়ে Gender নামে একটা   enum ক্রিয়েট করলাম যার ভেতরে আমরা তিনটি মেম্বার   Male ,Female আর  Unknown ইনক্লুড করেছি ।। enum  এক ধরনের টাইপ , তাই প্রত্যেক যায়গায় আমরা gender প্রোপারটিকে ইউস করার সময় তার আগে Gender ইউজ করে gender  কে enum  টাইপ করে নিয়েছি ।। এ ছাড়া , আহামরি কোনো চেইঞ্জ আমরা করে নি ।  আর বাকি যেসব ইউজ করেছি , আশা করি দুই-একটা কোড লিখলে এরকম সিনট্যাক্স অটোমেটিক রপ্ত হয়ে যাবে ।।

এখন খেয়াল করো , আগে আমরা যেখানে  1 /2 /3   কে   মেইল/ফিমেইল / আননোন    বানাতাম ,তার চেয়ে এখন আমাদের খুব সহজেই প্রোগ্রামটিকে বুঝতে সুবিধা হচ্ছে , তাই না ।।  অর্থাৎ প্রোগ্রামটি আগের চেয়ে আরো বেশি , readable ও maintainable  হয়েছে ,তাই না ?? এটাই আমাদের মূলত enum  ব্যবহারের উদ্দ্যেশ্য ।।

এবার একটু রেস্ট নিয়ে - এর পরের অংশটুকু শুরু করো ।।

আমরা যখন একটা enum ক্রিয়েট করি নরমাল ভাবে ।।  তখন , ডিফল্টভাবে কি হয় ??

public enum Gender
{
    Male,
    Female,
    Unknown
}

মুলত , এই এনামের  Underlying টাইপ হবে ইন্টিজার । আমরা ,  enum ক্রিয়েট করলে  তার মেম্বার গুলোকে কোনো ভ্যালুতে অ্যাসাইন না করলে ,অটোমেটিক কি অ্যাসাইন হয় ?? চলো দেখে আসি --

  public static void Main()
    {
       int[] values= (int[])Enum.GetValues(typeof(Gender));
       for (int i = 0; i < 3;i++ )
       {
           Console.WriteLine(values[i]);
       }
           Console.ReadKey();
      
    }

Enum নামে একটা  ক্লাস আছে আমাদের .Net ফ্রেমওয়ারকে ।। যার অনেকগুলো মেথোড আছে , যার ভেতরে একটি স্ট্যাটিক  GetValues মেথোড আছে   , যেটা Gender নামক এনামের মেম্বারগুলো'র ভ্যালু
রিটার্ন করে । কিন্তু , আমরা  typeof নামে আরো একটি মেথোড ব্যবহার করেছি ।। যেটা ,মূলত   Gender কোন টাইপের ? সেটা GetValues  মেথোডকে জানিয়ে দেয় ( এখানে enum টাইপ) ।।
এখন ঘটনা হলো , এই   GetValues মেথোড এর রিটার্ন টাইপ হলো স্ট্রিং টাইপ , তাই আমরা int[] দিয়ে সেটাকে টাইপ কাস্টিং করে নিলাম ।।  এবার চলো , এই দুই কোডকে একসাথে করে নিচে রান করে দেখি , কি হয় ???

using System;
using System.IO;


public class Joy
{
   
    public static void Main()
    {
       int[] values= (int[])Enum.GetValues(typeof(Gender));
       for (int i = 0; i < 3;i++ )
       {
           Console.WriteLine(values[i]);
       }
           Console.ReadKey();
      
    }

    }

public enum Gender
{
    Male,
    Female,
    Unknown
}

এবার রান করে দেখো , Male,Female,Unknown এই তিন মেম্বার এর ভ্যালু কি শো করায় ?? তুমি কোনো কিছু অ্যাসাইন  না করালেও , প্রথমটা শূণ্য আর পরের গুলো এক এক করে বাড়তে থাকে ।।
তুমি যদি নিচের মতো করে অ্যাসাইন করো ---

public enum Gender
{
    Male=2,
    Female,
    Unknown
}

তাহলে কি হবে ?? বলো তো -- পরের দুইটা কি হবে ?? আশা করি বুঝতে পেরেছো -- পরের দুইটার মান এক এক করে বাড়বে ।।
আমাদের আরো একটা মেথোড আছে , একটা enum  এর ভেতরে কি কি মেম্বার আছে ? সেটা প্রিন্ট করবার জন্য , চলো তার ব্যবহার দেখে আসি ।।

 public static void Main()
    {
       string[] values= Enum.GetNames(typeof(Gender));
       for (int i = 0; i < 3;i++ )
       {
           Console.WriteLine(values[i]);
       }
           Console.ReadKey();
      
    }

আমরা  GetNames মেথোড ইউজ করে এদের নাম শো করতে পারি ।।  তুমি শুধু এনামের মেম্বার এর টাইপ কে ইন্টিজার-এই রাখবে তা নয় ।। এটাকে , তুমি অন্যকিছুতে কনভার্ট করতে পারো চলো দেখে আসি ।।

using System;
using System.IO;


public class Joy
{
   
    public static void Main()
    {
       short[] values=(short[]) Enum.GetValues(typeof(Gender));
       for (int i = 0; i < 3;i++ )
       {
           Console.WriteLine(values[i]);
       }
           Console.ReadKey();
      
    }

    }

public enum Gender:short
{
    Male=2,
    Female,
    Unknown
}

আচ্ছা তুমি কিন্তু   Male,Female,Unknown এর প্রত্যেক এর মানই অ্যাসাইন করে দিতে পারবে , কোনো সমস্যা নাই ।। চলো দেখে আসি ---

using System;
using System.IO;


public class Joy
{
   
    public static void Main()
    {
       short[] values=(short[]) Enum.GetValues(typeof(Gender));
       for (int i = 0; i < 3;i++ )
       {
           Console.WriteLine(values[i]);
       }
           Console.ReadKey();
      
    }



    }

public enum Gender:short
{
    Male=2,
    Female=8,
    Unknown=34
}


তাহলে একটা জিনিস কিন্তু , আমরা শিউর যে - আমরা enum এর ডেটা টাইপ ছাড়াও এর মেম্বারগুলোর ভ্যালুও কাস্টোমাইজ করতে পারি ।। এর মানে আবার এটা মনে করো না যে , তুমি enum কে স্ট্রিং-এ কনভার্ট করতে পারবে ।। এটার ডিফল্ট ডেটা-টাইপ যেহেতু ইন্টিজার ,তাই একে short,long,ushort,ulong,uint ইত্যাদিতে কাস্টোমাইজ করতে পারবে ।।

এখন আমরা যেনো একটা বিষয় কনফিউজ করে না ফেলি , সেটা হলো -- Enum & enum । Enum  হলো একটা ক্লাস যার অনেকগুলো স্ট্যাটিক মেথোড আছে যেগুলোর সাহয্যে আমরা  enum  নামক ডেটা টাইপের মেম্বার গুলোর ভ্যালু ও নাম ইত্যাদি জানতে পারি ।। এই দুইটি জিনিস যেনো ,এক করে না ফেলি ।।

আচ্ছা , আরেকটা ইম্পরট্যান্ট বিষয় |  আমি যদি আরো একটা এনাম ক্রিয়েট করে একটার ভ্যালু আরেকটার সাথে অ্যাসাইন করতে চাই , তাহলে দেখি হয় কি না ??

public enum Gender
{
    Male,
    Female,
    Unknown
}

public enum Gonder
{
    Cricket,
    Football,
    Tennis
}

এখন আমি যদি একটা এলিমেন্ট এর সাথে আরেকটা অ্যাসাইন করাতে চাই , তাহলে কিভাবে করতে হয় ?? Gonder toy = (Gonder)Gender.Male;এইভাবে করতে হবে ।। না হলে , এরর খাবা ।।

তাহলে কম্পাইলার জানেই দুইটাই এনাম টাইপ, তারপরো আমরা অ্যাসাইন করাতে গেলে -- নাম উল্লেখ করে টাইপ কাস্টিং করতে হচ্ছে , তাই না ??? তাহলে বুঝতেই পারছো , এরা কতোটা টাইপ সেন্সিটিভ ?? এই কারণেই এদের   strongly typed constant  বলে ।।

যাই হোক আশা করি , enum  নিয়ে তোমাদের ছোটোখাটো একটা বেসিক ধারণা ক্লিয়ার হয়ে গেছে ।।
























  






C# For Beginners , Part-35 ( Exception Handling ,Why ? How ? When ? Basics,Inner Exception,Customize Exception,Exception abuse) )

ধরো তোমার পিসি'র নোটপ্যাড-এ তুমি কিছু একটা সেভ করে রেখেছো । তোমায় সেটা কন্সল স্ক্রিনে দেখাতে চাচ্ছো , তাহলে কি করবে ?? চলো ছোট একটা প্রোগ্রাম দেখে আসি ।
ধরো , তুমি joy1 নামে একটা ফাইল সেইভ করে রেখেছো নোটপ্যাডে ।। এখন সেটাকে সরাসরি সেখান থেকে কন্সল স্ক্রিনে শো করাতে চাও তাহলে -----------------------

using System;
using System.IO;

public class Joy
{

    public static void Main()
    {

        StreamReader streamreader = new StreamReader(@"C:\Users\Joy-PC\Documents\joy1.txt");
        Console.WriteLine(streamreader.ReadToEnd());
        streamreader.Close();
        Console.ReadKey();
    }
}


এখানে আমরা ,  using System.IO আগেই ব্যবহার করে নিয়েছি ।। কারণ , StreamReader ক্লাস'টি System.IO নামক নেইমস্পেইস এর অন্তর্ভুক্ত । তারপর , আমরা C:\Users\Joy-PC\Documents\joy1.txt এর মাধ্যমে সেই ফাইল এর ডিরেক্টরি লিখে ফেলি , StreamReader ক্লাস'টির কন্সট্রাক্টর এর মধ্যে  ।। আর , শুধু ব্ল্যাকস্ল্যাস ( \  ) আমরা ডাবল কোটেশন এর ভেতরে ইউজ করতে পারবো না , এটা একটা এসকেপ সিকুয়েন্স ক্যারেক্টার  । তাই , আগে @ ব্যবহারকরেছি ।। তারপর সেটা আমরা প্রিন্ট করেছি ।। আমরা এখানে , streamreader.Close() ব্যবহার এর মাধ্যমে , StreamReader ক্লাসের যে নতুন অবজেক্ট ক্রিয়েট করেছি তার সকল রিসোরস রিসোর্স মেমোরি থেকে ক্লিন করার জন্য ব্যবহার করেছি ।।

যাই হোক আমরা আজ যে বিষয়টি নিয়েই আলোচনা করবো সেটা হলো - Exception Handling | Exception হলো এক প্রকার Unforeseen Error যেটা আমাদের প্রোগ্রাম যখন এক্সিকিউট হয় , তখন ঘটে ।। ধরো , তুমিই তোমার  joy1.txt ফাইলের নাম চেইঞ্জ করে অন্য একটা নাম দিলে ।। তারপর উপরের কোড রান করো ,তাহলে কি হবে ??

স্ক্রিনে তুমি , কিছু হিজিবিজি লিকা দেখতে পাবে । আসলে এগুলো হলো এরর , যার প্রথমেই তুমি দেখতে পাবে -- "Unhandled Exception:System.IO.FileNotFound Exception..."
তাই না ?? এখানেই কিন্তু তুমি দেখতে পাচ্ছো সেই  Exception  এর কথা । আমরা কিন্তু , এই  "Unhandled Exception  " কে  handle করতে পারি ।। আজকে আমরা এগুলোই শিখবো ।।

আর তাছাড়াও এই  Exception এর যেসব তথ্য আউটুপুট-এ দেখাচ্ছে , এসব আমরা যারা নতুন তারা কিছু না বুঝলেও , এসব কিন্তু খুবই মূল্যবান অনেক তথ্য বহন করে হ্যাকারদের জন্য ।। তাই আমাদের অবশ্যই জানতে হবে ,  Exception  এর তথ্যগুলি কিভাবে ?? handle  করতে পারি ।। চলো একটা কোড দেখে আসি --

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
        try
        {
            StreamReader streamreader = new StreamReader(@"C:\Users\Joy-PC\Documents\joy.txt");
            Console.WriteLine(streamreader.ReadToEnd());
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }
        Console.ReadKey();
    }
}


আমাদের  .NET ফ্রেমওয়ার্কের খাতিরে -- একটা  Exception  ক্লাস দেয়াই আছে যার বেশ কয়েকটি প্রোপার্টি আছে ।। যার ভেতরে  Message & StackTrace প্রোপারটি মূলত আমাদের এক্সসেপশন সম্পরকে তথ্য ও ভূল প্রোগ্রামের  কতো নাম্বার লাইনে আছে ?? সেটা বলে দিবে ।। এখন তুমি বুঝবে কি করে ? কতো নাম্বার লাইন কোনটা ?? প্রথম প্রথম বুঝতে সমস্যা হতেপারে , সেই জন্য তোমায়
Cntrl+G প্রেইস করলেই ।। একটা ফর্ম আসবে , সেখানে তুমি যতো নাম্বার লিখবে ? তোমায় ততো নাম্বার লাইনে মাউস  এর দাগ চলে যাবে। দেখে নাও ... এখানে আমরা  try ও  catch ব্লক ইউজ করেছি । যদি কোনো এক্সসেপশন নাই থাকতো , তাহলে  catch ব্লকের কোনো কিছু প্রিন্ট হবে না । কিন্তু , try  ব্লকে কোনো এক্সসেপশন থাকলে সেটা catch  ব্লকে প্রিন্ট করবে ।।

এখন একটা জিনিস আমাদের জেনে রাখতে হবে , উপরে যেটা ঘটছে , সেটা মূলত  FileNotFound Exception । এটাও একটা ক্লাস ,যেটা  Exception ক্লাস থেকে ইনহেরিটেড হয়েছে ।। চলো একটু দেখে আসি -----

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
        try
        {
            StreamReader streamreader = new StreamReader(@"C:\Users\Joy-PC\Documents\joy.txt");
            Console.WriteLine(streamreader.ReadToEnd());
        }
        catch(FileNotFoundException ex)
        {
            Console.WriteLine("{0} File May Doesn't Exist, Please Check\n\n\n", ex.FileName);

            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }
        Console.ReadKey();
    }
}


এখানে আমরা ,  FileNotFoundException  ক্লাস ব্যবহার করেছি ।। যার একটা প্রোপার্টি আছে    FileName নামে ।। যার সাহা্য্যে , আমরা ফাইলের নামটিও শো করাতে পারছি ,যে ফাইল থেকে আমরা রিড করতে চাচ্ছিলাম ।।  প্রোগ্রামটি রান করিয়ে দেখে নাও , আর তারপর আমরা  Message ও  StackTrace প্রোপার্টির দ্বারা অনেক মেসেজ শো করাই ।।   তুমি কি বুঝতে পারছো যে -- একটু একটু করে তুমি   Exception Handling করা শুরু করেছো ।।

নীচের কোড দেখে আসি চলো -------------------------

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
        try
        {
            StreamReader streamreader = new StreamReader(@"C:\UsersJoy-PC\Documents\joy.txt");
            Console.WriteLine(streamreader.ReadToEnd());
        }
        catch(FileNotFoundException ex)
        {
            Console.WriteLine("{0} File May Doesn't Exist, Please Check\n\n\n", ex.FileName);

            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }
      
        Console.ReadKey();
    }
}


এখানে আমরা কিন্তু , ফাইলের ডিরেক্টরি ইচ্ছে করে আমি বদলে দিয়েছি ,খেয়াল করে দেখো ।। এখন আমি যদি রান করাই তাহলে কি হবে ??? আউটপুটে দেখবে ---DirectoryNotFoundException তাই না ?? এর মানে ?? এটা  FileNotFoundException  নয় ।। তাই তুমি , FileNotFoundException  এর  catch ব্লক দিয়ে DirectoryNotFoundException এক্সশেপশন কে হ্যান্ডল করতে পারবে না । তুমি উপরের কোড রান করে দেখো , তূমি যেটা শো  করাতে চাইছিলে সেটা কিন্তু কনসল স্ক্রিনে দেখাচ্ছে না। একটু ভালো করে খেয়াল করে দেখো ।। 

তাহলে  DirectoryNotFoundException  এর ক্ষেত্রে তুমি কি কি করবে ?? বুঝতেই পারছো , DirectoryNotFoundException  ক্লাস অথবা সবার মাদার ক্লাস Exception ক্লাসও ব্যবহার করতে পারো ।। তবে , DirectoryNotFoundException  ক্লাসের কিন্তু কোনো  FileName প্রোপার্টি নেই , সেদিকে খেয়াল রেখো ।।

এখান থেকে কিন্তু আমরা বড়ো একটা ব্যপার এর বাস্তব রুপ শিখে গেছি , সেটা কি ?? ইনহেরিটেন্স এর কারণে , আমাদের বেইস ক্লাস Exception এর রেফারেন্স ভ্যারিয়েবল যেকোনো স্পেসিফিক ডেরাইভড Exception ক্লাস এর অব্জেক্ট কে পয়েন্ট করতে পারছে ।। এটা কিন্তু ইনহেরিটেন্স এর বড়ো একটা উদাহরণ ।।

আরো একটা বিষয় , মাথায় রাখা উচিত ।সেটা হলো , স্পেসিফিক ক্লাস যেমন FileNotFoundException  ক্লাস কিন্তু এর বেইস ক্লাস Exception এর আগে  বসবে ।। এটা মাথায় রাখতে হবে ।।

একটা বিষয় আরো ক্লিয়ার হওয়া উচিত , সেটা হলো আমরা যখন try ব্লকে  streamreader.Close(); ইউজ করছি , সেটা কি কখনো কাজ করছে ?? নাকি করছে না ?? আসলে এই লাইন আসার
আগেই যদি কখনো Exception হয়ে যায় , তাহলে । তাহলে কিন্তু ঐ লাইন এক্সিকিউট হয় না । এর মানে ,হিপ মেমোরি থেকে এসব রিসোর্স গুলো ফ্রি হয় না ।। যেটা আমাদের অবশ্যই মাথায় রাখা উচিত ।।
তাহলে কি করবো এখোন ?? হুম ,একটা আরো  ব্লক ইউজ করা যায় -যার নাম হলো  finally ব্লক । যার ভেতরে আমরা streamreader.Close(); ইউজ করবো । কারণ , Exception থাকুক আর নাই থাকুক । আমাদের এই  finally ব্লক এক্সিকিউট হবেই ।।
 try

        {
            StreamReader streamreader = new StreamReader(@"C:\UsersJoy-PC\Documents\joy.txt");
            Console.WriteLine(streamreader.ReadToEnd());
            streamreader.Close();
        }

চলো  আমরা একবার একটা প্রোগ্রাম দেখে আসি  , এটা নিয়ে ।।
using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
        StreamReader streamreader = null;
        try

        {
             streamreader = new StreamReader(@"C:\UsersJoy-PC\Documents\joy.txt");
            Console.WriteLine(streamreader.ReadToEnd());
            streamreader.Close();
        }
            catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally
        {
            Console.WriteLine("Finally block Executed!!");
            Console.ReadKey();
            streamreader.Close();
        }
      
        Console.ReadKey();
    }
}

 এটা  Exception সহ  ছিলো ।। এখন একটা Exception ছাড়া কোড লিখে দেখি ----  finally ব্লক এক্সিকিউট হয় কি না ?? চলো --------------

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
        StreamReader streamreader = null;
        try

        {
             streamreader = new StreamReader(@"C:\Users\Joy-PC\Documents\joy1.txt");
            Console.WriteLine(streamreader.ReadToEnd());
            streamreader.Close();
        }
            catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally
        {
            Console.WriteLine("Finally block Executed!!");
            Console.ReadKey();
            streamreader.Close();
        }
      
        Console.ReadKey();
    }
}

 এবার  Exception ছাড়াই দেখলাম , দুই ক্ষেত্রেই কিন্তু আমাদের finally ব্লক এক্সিকিউট হয়েছে । সো , আমরা এই ব্লক ইউজ করবো  ।।   আবার অনেক Exception এর ক্ষেত্রে যদি StreamReader ক্লাসের অবজেক্ট  ফাইল থেকে রিড নাই করতে পারে  ( মানে , Exception থাকে )  তাহলে , StreamReader ক্লাসের অব্জেক্ট নালই থেকে যায় ।। তাই , finally ব্লকের এক্সিকিউট হয় না । তাই আমরা জিনিসটাকে আরো একটু সুন্দরভাবে এইভাবে লিখতে পারি --

finally
        {
              if( streamreader!=null){
            Console.WriteLine("Finally block Executed!!");
            Console.ReadKey();
            streamreader.Close();
                   }
        }

আশা করি , বিষয়টা খুবই স্পষ্ট হয়েছে ।।  এখানে আরো একটি প্রশ্ন মনের ভেতরে আসতেই পারে , আমাদের - সেটা হলো ,আমরা শুধু শুধু আরো একটা finally নামে একটা ব্লক খুলে কোডগুলো এক্সিকিউট করালাম কেনো ?? আমরা তো এই ব্লকের ভেতরের কোডগুলো এমনিতেই লিখতে পারতাম , এই ব্লক ছাড়া - তাতে কি অসুবিধা হত ??

প্রশ্নটি খুবই ভালো প্রশ্ন , কিন্তু - একটি কথা জেনে রাখা উচিত ।। যদি , আমাদের কোনো এক ধরণের  Exception হয়েই থাকে এবং সেটার ফলে StreamReader ক্লাসের অব্জেক্ট নাল নাই থাকে । তাহলে ,ক্যাচ ব্লকে ঢোকার পরে এটা এর পরের আর কোনো কোড এক্সিকিউট করতে দিবে না , তাই আমরা সবসময় finally ব্লকই ইউজ করবো ,এটা খুবই ভালো একটা অভ্যাস ।।

আচ্ছা যাই হোক , এবার আমরা একটু বিরতি নিয়ে তারপর এরপরের আলোচনা শুরু করবো ।। তোমরা যারা আছো , তারা উপরের অংশটুকুই আগে ভালো করে বোঝার টড়াই করো , তারপর নিচের অংশটুকু বোঝা যাবে ।।

চলো এবার আমরা একটা সংখ্যাকে শূণ্য দ্বারা ভাগ দিয়ে দেখি , কি ধরনের Exception হয় ??? নীচে কোড দেখে আসি চলো ---

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
       
        try

        {
            int a = Convert.ToInt32(Console.ReadLine());
            int b = Convert.ToInt32(Console.ReadLine());
            int result = a / b;
            Console.WriteLine(result);
           
        }
            catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
      
      
        Console.ReadKey();
    }
}

এখন ধরো , এটা কোন ধরনের  Exception ?? সেটা আমরা যে ফাইল থেকে এতদিন রিড করেছি , সেই ফাইলে রাইট করি ( লিখে ফেলি ) ।। দেখি চলো কোড ----------

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
       
        try

        {
            int a = Convert.ToInt32(Console.ReadLine());
            int b = Convert.ToInt32(Console.ReadLine());
            int result = a / b;
            Console.WriteLine(result);
           
        }

            catch(Exception ex)
        {
            string filepath = @"C:\Users\Joy-PC\Documents\joy1.txt";
                 StreamWriter sw=new StreamWriter (filepath);
                 sw.WriteLine(ex.GetType().Name);
                 sw.Close();
          
        }
      
      
        Console.ReadKey();
    }
}


এখানে আমরা কোন ধরনের Exception ? সেটা জানার জন্য  GetType() মেথোড এবং এর  প্রোপার্টি  Name ইউজ করছি ।। এখন উপরের কোড রান করে - তারপর ঠিকঠাক দুইটি আউটপুট এর প্রথমটি যেকোনো নাম্বার দাও আর , সেকেন্ড নাম্বারটি শূণ্য দাও । তাহলে তুমি , তারপরে তোমার যে ফাইলে সেইভ করছো - সেখানে গিয়ে দেখো । অটোমেটিক , তোমার ঐ ফাইলে এটা যে ধরনের  Exception ( DivideByZeroException ) লিখা উঠে গেছে ।। এভাবে আমরা অনেক কিছুই ফাইলে লিখাতে পারবে , যেমন  Message প্রপার্টি সহ অনেককিছুই  | ।

আচ্ছা এবার আসো পুরোনো কথায় - আমি যে ফাইল ডিরেক্টরি লিখেছি , সেটা ভুল লিখতে চাই এর মানে ( FileNotFound Exception) ঘটাতে চাই চলো দেখি কি করা যায় ???

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
       
        try

        {
            int a = Convert.ToInt32(Console.ReadLine());
            int b = Convert.ToInt32(Console.ReadLine());
            int result = a / b;
            Console.WriteLine(result);
           
        }

            catch(Exception ex)
        {
            string filepath = @"C:\Users\Joy-PC\Documents\joy.txt";
            if (File.Exists(filepath))
            {
                StreamWriter sw = new StreamWriter(filepath);
                sw.WriteLine(ex.GetType().Name);
                sw.Close();
            }
            else
            {
                throw new FileNotFoundException(filepath + "is not found", ex);
            }
          
        }   
    }
}

 উপরের কোডটি রান করে দেখো । তাহলে কি দেখলে ??? আমাদের উদ্দেশ্য ছিলো  DivideByZeroException , কিন্তু - আমরা নতুন একটা উটকো ঝামেলা  FileNotFoundException । কিন্তু এই দুইটা  Exception আনার পরে ।। আমরা কোনোটাই হ্যান্ডেল করতে পারছি না ।।

 সেকেন্ডটার জন্য , প্রথম Exception টাও এখন ফাইলে রাইট করে পারছি না । তো চলো , এই সমস্যা থেকে কিভাবে ,উদ্ধার পাওয়া যায় ?? সেই চেষ্টা করি ।। আচ্ছা একটা জিনিস ক্লিয়ার হয়ে নেই যে - আমাদের একদম প্রথম Exception ছিলো DivideByZeroException , তাই না ?? আর তারপরের সেকেন্ড  Exception টা হলো --  FileNotFoundException ।। প্রোগ্রামের ভাষায় আমরা প্রথম টাকে InnerException বলবো , আর পরেরটাকে Current Exception বলবো , ঠিক আছে ??? চলো এবার আসল কাজটা সেরে আসি --

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
        try
        {
            try
            {
                int a = Convert.ToInt32(Console.ReadLine());
                int b = Convert.ToInt32(Console.ReadLine());
                int result = a / b;
                Console.WriteLine(result);

            }

            catch (Exception ex)
            {
                string filepath = @"C:\Users\Joy-PC\Documents\joy.txt";
                if (File.Exists(filepath))
                {
                    StreamWriter sw = new StreamWriter(filepath);
                    sw.WriteLine(ex.GetType().Name);
                    sw.Close();
                }
                else
                {
                    throw new FileNotFoundException(filepath + "is not found", ex);
                }

            }
        }
        catch(Exception es)
        {
            Console.WriteLine("Current Exception = {0}", es.GetType().Name);
            Console.WriteLine("Inner Exception = {0}", es.InnerException.GetType().Name);
            Console.ReadKey();
        }
       
    }
}

 তাহলে এখানে আমরা আরো একটা try & catch ইউজ করলাম , কেনো ?? কারণ আমরা  যদি  প্রথমেই   Exception পাই , তাহলে সেটাকে  catch  করার জন্য ভেতরে  একটা catch  ব্লক ইউজ করেছি , তাই না ?? কিন্তু যখন , সেই  catch ব্লকেও  Exception পাবো , তখন কি করবো , তাই আরো এই পুরোটাকেই একটা try ব্লকে ঢুকিয়ে দিয়েছি এবং তারপর আরো একটা  catch  ব্লক বাইরে ইউজ করেছি ।।  আশা করি এইটুকু বুঝতে পেরেছো ।। এখন , নতুনত্ব বলতে আমরা ভেতরের ক্যাচ ব্লকের Exception এর জন্য , InnerException ইউজ করেছি , এইটুকুই । এখানে কিন্তু একটা কাহিনি আছে  throw new FileNotFoundException(filepath + "is not found", ex); এর মাধ্যমে কিন্তু আসলে আমরা ওই প্রথম Exception এর রেফারেন্স ভ্যারিয়েবল ( অব্জেক্ট ) আমাদের নতুন বাইরের Exception ক্লাসে পাঠিয়ে দিয়েছি । যা InnerException তে পয়েন্ট করা আছে , এই কারণেই --- es.InnerException.GetType().Name লিখলে সেই ভেতরের  Exception এর টাইপ পেয়ে যাচ্ছো । আশা করি , বিষয়টা ক্লিয়ার হয়েছে ।।


আচ্ছা একটা বিষয় পরিষ্কার করেই নেই , তুমি যদি শুধু আউটার  Exception শো করাতে চাও , তাহলে কি করতে হবে ?? চলো দেখে আসি --

using System;

using System.IO;

public class Joy
{

    public static void Main()
    {
        try
        {
            try
            {
                int a = Convert.ToInt32(Console.ReadLine());
                int b = Convert.ToInt32(Console.ReadLine());
                int result = a / b;
                Console.WriteLine(result);

            }

            catch (Exception ex)
            {
                string filepath = @"C:\Users\Joy-PC\Documents\joy.txt";
                if (File.Exists(filepath))
                {
                    StreamWriter sw = new StreamWriter(filepath);
                    sw.WriteLine(ex.GetType().Name);
                    sw.Close();
                }
                else
                {
                    throw new FileNotFoundException(filepath + "is not found");
                }

            }
        }
        catch(Exception es)
        {
            Console.WriteLine("Current Exception = {0}", es.GetType().Name);
            if (es.InnerException != null)
            {
                Console.WriteLine("Inner Exception = {0}", es.InnerException.GetType().Name);
            }
            Console.ReadKey();
        } 
    }
}

 এখানে , যেহেতু আমরা শুধু একটা মাত্র মানে , সেকেন্ড'টা শো করাতে চাই । তাহলে ভেতরের কন্সট্রাক্টরে ওই ( অরিজিনাল / ইনার )  Exception এর রেফারেন্স ভ্যারিয়েবল পাস করাবো না । আর এইদিকে , যদি আমি প্যারামিটার কনস্ট্রাক্টরে পাস না করাই ।। তাহলে এদিকে আমাদের বাইরের  Exception ক্লাসের গুরুত্বপূর্ণ একটা প্রোপার্টি  InnerException টা নাল থাকবে , আর তাই আমি একটা  if স্টেইটমেন্ট ইউজ করে , চেইক করে দেখালাম  es.InnerException != null যদি খালি না হয় , তাহলেই শুধুমাত্র  Console.WriteLine("Inner Exception = {0}", es.InnerException.GetType().Name); লাইন প্রিন্ট করবে  অন্যথায় প্রিন্ট করবে না  ।।  আশা করি বিষয়গুলো আরো ক্লিয়ার হচ্ছে ।।

আচ্ছা এখন কিছুটা বিরতি নিয়ে আমরা এর পরের বিষয়গুলো আলোচনা করবো , এর পরের আলোচনা দেখার আগে ---- আগেরটুকু ভালো করে পড়ে ও বুঝে নেয়া উচিত ।।


আমরা , আমাদের  Exception এর সময় যে যে মেসেজ শো করে সেটা এক এক Exception অনুযায়ী এক এক রকম , এখানে আমাদের কোনো হাত নেই , আমরা শুধু কখন কোনটা দেখাবে ?? শুধু এইটুকুই হ্যান্ডল করতে পারি ।।  কিন্তু আমরা যদি কখনো নিজে নিজেই নতুন নতুন  Exception ক্রিয়েট করে কাস্টমাইজ করতে পারতাম  ! তাহলে ভালৈ হতো , চলো দেখে আসি ।।

এটা দেখার আগে , ইনহেরিটেন্স ও এক্সশেপশন নিয়ে বেসিক একদম ক্লিয়ার থাকতে হবে , না হলে এই বিষয়টা একদমই অন্যরকম লাগবে ।। চলো ......।।


প্রথমে আমরা একটা ক্লাস খুলে , সেটার বেইস ক্লাস হিসেবে Exception ক্লাস বসিয়ে দেবো , অন্যথায় আমরা আমাদের মতো করে কাজ করাতে পারবো না । তারপর , আমরা তিনটা কন্সট্রাক্টর ক্রিয়েট করবো ।। আগে আমরা , throw new Exception(); লিখে ভেতরে কিছু লিখলেই শো করাতো , কারণ এদের ডিফল্ট কন্সট্রাক্টর আছে , কিন্তু আমরা নতুন যে নতুন  Exception ক্লাস বানিয়েছি , তাতে --
কোনো ডিফল্ট কন্সট্রাক্টর তো নেই তাই আমরা , আমাদের নতুন ক্লাসের বেইস ক্লাস এর কন্সট্রাক্টরকেই ইউজ করবো , তাহলে কষ্ট করে আর লিখতে হবে না ।

  public class UserLoggedInException :Exception
    {
        public UserLoggedInException():base()
        {

        }
        public UserLoggedInException(string Message):base(Message)
        {

        }
        public UserLoggedInException(string Message,Exception innerException):base(Message,innerException)
        {

        }
    }

আমরা শুধু কাস্টমাইজই নয় , আমাদের বানানো Exception ক্লাসের যদি কখনো  innerException ট্র্যাক করানোরও প্রয়োজন পড়ে , তখন আমরা তিন নাম্বার কন্সট্রাক্টর দিয়ে শো করাতে পারবো ।।
আচ্ছা এখন একদমই নতুন একটা বিষয় নিয়ে জানবো , সেটা হলো ---------------- অ্যাপ্লিকেশন ডমেইন । আমাদের এই বানানো ক্লাসটি সাধারণত তখনই কাজ করবে ,যখন সেইম অ্যাপ্লিকেশন ডোমেইন থাকবে ।। এর মানে , ধরো - আমার দুইটা  অ্যাপ্লিকেশন আছে একটার নাম  A & আরো একটার নাম হলো  B  | এই অ্যাপ্লিকেশন দুইটি  একে অপরের সাথে কথা বলতে চায় , তাহলে ?? কি করতে হবে ?? A অ্যাপ্লিকেশনের অবজেক্টগুলোকে B অ্যাপ্লিকেশনের যে বাউন্ডারি আছে , সেটা ক্রস করতে হবে । আর এই জন্য দুইটা  অ্যাপ্লিকেশন এরই অব্জেক্টগুলোকে সিরিয়ালাইজেশন করতে হবে , তাহলে তুমি যদি তোমার অব্জেক্ট গুলোকে এক অ্যাপ্লিকেশন ডোমেইন থেকে অন্য অ্যাপ্লিকেশন ডোমেইন-এ মুভ করাএ চাও তাহলে একটা প্যাকেজ আকারে একটা থেকে আরেকটায় মুভ করতে পারে , এই জন্য অব্জেক্টগুলোকে সিরিয়ালাইজেশন করতে হবে । তাহলে চলো সিরিয়ালাইজেশন  করে এর জন্য আরো একটা কন্সট্রাক্টর ক্রিয়েট করে ফেলি ----

using System;
using System.IO;
using System.Runtime.Serialization;

public class Joy
{

    public static void Main()
    {
        throw new UserLoggedInException("User Is already Logged In , No Duplicate ");
           
        }
    [Serializable]
    public class UserLoggedInException :Exception
    {
        public UserLoggedInException():base()
        {

        }
        public UserLoggedInException(string Message):base(Message)
        {

        }
        public UserLoggedInException(string Message,Exception innerException):base(Message,innerException)
        {

        }
        public UserLoggedInException(SerializationInfo info,StreamingContext context ):base(info,context)
        {

        }
    }
    }

নতুনত্বের মধ্যে আমরা নতুন সিস্টেম ইঙ্কলুড করেছি ------খেয়াল করে দেখে নাও , আপাতত এই  সিরিয়ালাইজেশন  নিয়ে না ভাবলেও চলবে , বাট একটু বেসিক জেনে রাখা ভালো ।।

সব শেষে আমাদের আরো একটা বিষয় ক্লিয়ার হওয়া উচিত যে , এই  Exception এর শুধু শুধু ব্যবহার যেনো না করি ।। যেমন আমরা ,নিচের মতো করে যেনো না করি ।

using System;
using System.IO;
using System.Runtime.Serialization;

public class Joy
{

    public static void Main()
    {
        try
        {
            int a = Convert.ToInt32(Console.ReadLine());
        }
        catch(Exception ex)
        {
            Console.WriteLine("InputFormat Is Not Correct");
            Console.ReadKey();
        }
           
        }
  
    }
এরকমভাবে খুব শজেই আমরা লিখতে পারি , বাট এইসব ছোটখাট বিষয়ে  Try.Parse মেথোড ইউজ করলেই পারি , তা সত্ত্বেও -- শুধু শুধু  Exception ইউজ করা ঠিক হবে না ।। চলো , Try.Parse  মেথোড দিয়ে করে আসি একবার -----------

using System;
using System.IO;
using System.Runtime.Serialization;

public class Joy
{

    public static void Main()
    {
            int result = 0;
            bool IsPossible = Int32.TryParse(Console.ReadLine(),out result);
            if(IsPossible)
            {
                Console.WriteLine("Your Input Is {0}", result);
            }
            else
            {
                Console.WriteLine("Input Format Isn't Correct");
            }
       

           
        }
  
    }

আশা করি বুঝতে পেরেছো , এসব ক্ষেত্রে আমরা শুধু শুধু  Exception ইউজ করবো না ।। যাই হোক আজ এইটুকুই ---------------------------------------