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 ইউজ করবো না ।। যাই হোক আজ এইটুকুই ---------------------------------------























Tuesday, October 17, 2017

C# For Beginners , Part -32 ( Multiple Class InheriTance Problem & Solution )

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


আজকে আমরা , মাল্টিপল ক্লাস ইনহেরিটেন্স কেনো করা যায় না ?? সেটা নিয়ে কথা বলবো ।।
চলো আগে একটা ছবি দেখে আসি ------------------------------------------------

আমরা উপরের ছবি অনুসারে একটা প্রোগ্রাম লিখেই ফেলি ।। চলো ------------------------

using System;

public  class  A
{
    public virtual void display()
    {
        Console.WriteLine("Class A Implementation");
    }
}

public  class B:A
{
    public override void display()
    {
        Console.WriteLine(" This is class B Implementation");
    }
}

public class C : A
{
    public override void display()
    {
        Console.WriteLine(" This is class B Implementation");
    }
}

public class D:B,C
{

}

public class Program
{
    public static void Main()
    {
        D d = new D();
        d.print();
        Console.ReadKey();
       
    }

}



যদিও , একের অধিক ক্লাস থেকে একটা ক্লাস ইনহেরিটেড করা যায় না ।। তারপরো , মেনে নিলাম আমরা যে ,  D ক্লাস B এবং C উভয় থেকেই , ইনহেরিটেড হতে পারে ।। তাহলে , এটা যদি সত্যি সত্যি রান করানো যেতো , তাহলে কি আউটপুট পেতা ??? একটু চিন্তা করো তো ??? আমরা যখন , D ক্লাস এর একটা অব্জেক্ট ক্রিয়েট করলাম , তখন -- এটাকে মেইনমেথোড এ কল করলে , তখন D ক্লাস যেহেতু দুইটা ক্লাস B এবং C উভয় থেকেই , ইনহেরিটেড হয়েছে তাই কোন ক্লাসের মেথোড'কে কন্সল স্ক্রিনে শো করবে ?? সেটা ডিটারমাইন করবে কিভাবে ??  এই কারণে , আমরা একাধিক ক্লাস থেকে একটা ক্লাসকে ইনহেরিটেড করতে পারি না ।। এই সমস্যা কে , বলা হয় ডায়মন্ড প্রবলেম ( Diamond ) ।। 


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

আমরা , দুইটা ক্লাস ক্রিয়েট করবো  B  &  C  নাম দিয়ে ।। তারপর সেই দুইটা ক্লাস থেকে ইনহেরিটেড করে আরো একটা ক্লাস ক্রিয়েট করবো  D নামে , তবে ইনহেরিটেড করবো - ইন্টারফেইস দিয়ে  ।। চলো দেখে আসি ,

using System;

 interface IB
{
     void Bdisplay();
}
  class B:IB
{
    public  void Bdisplay()
    {
        Console.WriteLine(" This is class B Implementation");
    }
}

 interface IC
{
     void Cdisplay();
}
 class C:IC
{
    public void Cdisplay()
    {
        Console.WriteLine(" This is class C Implementation");
    }
}

public class D:IC,IB
{
    B b = new B();
    C c = new C();
    public void Bdisplay()
    {
        b.Bdisplay();
    }
    public void Cdisplay()
    {
        c.Cdisplay();
    }

}

public class Program
{
    public static void Main()
    {
        D d = new D();
        d.Bdisplay();
        d.Cdisplay();
        Console.ReadKey();
       
    }

}

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

তো , আশা করি , সামনে বিষয়গুলই আরো ক্লিয়ার হবে ।। আজ এইটুকুই -----------




















C# For Beginners , Part - 31 ( Abstract Classes Basics, Differences Between Abstract Calsses & Interface)

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


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

চলো সিম্পল দেখে আসি ----

using System;

public abstract class Customer
{
    public void print()
    {
        Console.WriteLine("Hey Joy");
    }
}
public class Program
{
    public static void Main()
    {
        Customer r = new Customer();
        r.print();
        Console.ReadKey();
    }

}

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

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

using System;

public abstract class Customer
{
    public abstract void print();
   
}
public class joy : Customer
{
    public override void print()
    {
        Console.WriteLine("Hey Joy");
    }
}
public class Program
{
    public static void Main()
    {
        joy r = new joy();
        r.print();
        Console.ReadKey();
    }

}


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


 public abstract class Customer
{
     private abstract void print();                              public abstract class Customer
                                                                            {
   }                                                                             abstract void print();       
                                                                                }


উপরের যে কোনো একটার মতো করে লিখলে এরর খাবা ।। অ্যাবস্ট্রাক্ট মেম্বার কখনো প্রাইভেট হতে পারে না ।। কিন্তু , অ্যাবস্ট্রাক্ট ক্লাসের ভেতরের নরমাল মেথোড ইমপ্লিমেন্টেশন পাবলিক / অরাইভেট হতে পারে ।।

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

using System;

public abstract class Customer
{
   public abstract void print();
   
   
}
public class joy : Customer
{
   public override void print()
   {
       Console.WriteLine("Hi");
   }
}
public class Program
{
    public static void Main()
    {
        Customer r = new joy();
        r.print();
        Console.ReadKey();
    }

}



তুমি এই ক্ষেত্রে ইনহেরিটেন্স এর ক্ষেত্রে ঠিকই ইটারফেইস এর মতোই একটা অ্যাবস্ট্রাক্ট থেকে আরো একটা অ্যাবস্ট্রাক্ট ক্লাস ইনহেরিটেড করতে পারবা ----

public abstract class Customer
{
   public abstract void print();
   
   
}
public abstract class joy : Customer
{
    public abstract void print1();
  
}

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

public abstract class Customer
{
   public abstract void print();
   
   
}
public abstract class joy : Customer
{
    public abstract void print1();
  
}

public class jony : joy
{
    public override void print1()
    {
       
    }

    public override void print()
    {
       
    }
   
}

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

public sealed abstract class Customer

{
   public abstract void print();
}


তুমি কিনতু , ইন্টারফেইস -এর ক্ষেত্রে ক্লাস ফিল্ড ইউজ করতে পারতে না , বাট এখানে সেটা ইউজ করতে পারবে ।।

public  abstract class Customer
{
    public int id;
    public string name;
   public abstract void print();
  
}



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

public interface joy
{

}

public  abstract class ICustomer:joy
{
  
}

বাট  অ্যাবস্ট্রাক্ট ক্লাস থেকে , ইন্টারফেইস ইনহেরিটেড করা যায় না ।।

public abstract class  joy
{

}

public  interface ICustomer:joy
{
  
}

 অ্যাবস্ট্রাক্ট ক্লাস থেকে , ইন্টারফেইস ইনহেরিটেড করলে এরর খাবা ।।

আরো একটি বিষয় জেনে রাখা উচিত - একটা ক্লাস একাধিক ইন্টারফেইস থেকে ইনহেরিটেড হতে পারে , বাট একটা ক্লাস একাধিক অ্যাবস্ট্রাক্ট ক্লাস থেকে ইনহেরিটেড হতে পারে না ।।


যাই হোক , মোটামুটি অ্যাবস্ট্রাক্ট ক্লাস এর ফিয়েচার /সিন্ট্যাক্স নিয়ে কিছু বেসিক আলোচনা হলো , সামনে আরো ডিটেইলস আলোচনা করবো , আজ এইটুকুই --------------