• Inheritance →

    class Parent
    {
        public int X { get; protected set; }
        public int Y { get; protected set; }
    
        public Parent(int _X , int _Y)
        {
            X = _X;
            Y = _Y;
            Console.WriteLine("Base Ctor");
        }
    
        public int Product() { return X * Y; }
    
        public override string ToString()
        {
            return $"({X},{Y})";
        }
    
    }
    
    class Child:Parent
    {
        public int Z { get; protected set; }
    
        public Child(int _X , int _Y , int _Z)
            :base(_X,_Y) ///Base Ctor Chaining 
        {
            Z = _Z;
            Console.WriteLine("Child Ctor");
        }
    
        public new int Product () 
        {
            return Z * base.Product();
            //return X * Y * Z; 
        }
    
        public override string ToString()
        {
            return $"{X},{Y},{Z}";
        }
        
    }
    
    class program
    {
    		static void Main()
    		{
    			    Parent P = new Parent(1, 2);
              Console.WriteLine(P.Product());
    
              Child C = new Child(3, 4, 5);
    
              Console.WriteLine(C.Product()); ///Derived
    
              ///Not Valid C# Code
              //keyword base used only inside Derived class not Outside
              //Console.WriteLine(C.base.Product() );
    		}
    }
    

  • Abstract Class →

    //class created to be base class for childs
    // can't intialize object from abstract class
    abstract class Person
    {
        public string FName { get; set; }
        public string LName { get; set; }
    
        public Person(string _FName , string _LName)
        {
            FName = _FName;
            LName = _LName;
        }
    
        public override string ToString()
        {
            return $"{FName} {LName}";
        }
    }
    
    //valid
    Person P;
    
    //not Valid
    //Person P1 = new Person("Ahmed", "Ali");
    
    abstract class GeoShape
    {
        public int Dim1 { get; set; }
        public int Dim2 { get; set; }
    
        public GeoShape(int D1 , int D2) { Dim1 = D1; Dim2 = D2; }
    
        //public virtual Double Area () =0; //C++
    
        public abstract Double Area(); 
        ///Abstract Method = Virtual + No Impelementation
    
        public abstract double Perimeter { get; /*set;*/ } 
        ///Abstract ReadOnly Property
    
    }
    
    abstract class RectBase : GeoShape
    {
        public RectBase(int W=0, int H=0) : base(W, H) { }
    
        public override double Area()
        {
            return Dim1 * Dim2;
        }
    
    }
    
    class Rect : RectBase
    {
        public override double Perimeter { get { return 2 * (Dim1 + Dim2); } }
    }
    
    class Square : RectBase
    {
        ///Must
        // because perimeter didn't implemented in rectbase
        public override double Perimeter => 4 * Dim2;
        ///Optional
        // because Area implemented in rectbase
        public override double Area()
        {
            throw new NotImplementedException();
        }
    }
    

  • Equality →

    Screenshot 2024-06-13 155446.png

    • Class Equality →

      • There is 4 ways to check equality all are System.Object Members.
      1. public virtual bool Equals(Object O2) { } → Reference Equality
      2. public static bool Equals(Object O1, Object O2) { return O1.Equals(O2); } → Reference Equality
      3. public static bool ReferenceEquals(Object O1, Object O2) { } → Reference Equality
      4. Operator == → Reference Equality
      public class Point:IComparable<Point>
      {
          public int X { get; set; }
          public int Y { get; set; }
      
          public int CompareTo( Point other)
          {
              if (other == null) return 1;
      
              if (X == other.X)
                  return Y.CompareTo(other.Y);
              return X.CompareTo(other.X);
          }
      
          public override bool Equals(object obj)
          {
              #region Casting
              //Point Right = (Point)obj; /// unSafe Casting 
      
              //if (obj is Point) ///is -> return false if casting 
              //will Fail , no exceptions will be thrown
              //{
              //    Point Right = (Point)obj;
              //    return (X == Right.X) && (Y == Right.Y);
              //}
      
              //if (obj is Point Right) ///is return false if 
              //casting will Fail , no exceptions will be thrown
              //    return (X == Right.X) && (Y == Right.Y);
      
              //return false; 
              #endregion
      
              Point Right = obj as Point; ///as -> return null if 
              //Casting Fails , no exception will be thrown
      
              if (Right == null) return false;
      
              if (this.GetType() != obj.GetType()) return false;
      
              if (object.ReferenceEquals(this, Right)) return true;
      
              return (X == Right.X) && (Y == Right.Y);
          }
      
          public override string ToString()
          {
              return $"({X},{Y})";
          }
      
      }
      
      class program
      {
      		static void Main(string[] args)
      	{
      		    Point P1 = new Point() { X = 5, Y = 10 };
              Point P2 = new Point() { X = 5, Y = 10 };
              Point P3 = P1;
              Point3D P4 = new Point3D() { X = 5, Y = 10, Z = 15 };
      
              //P2 = default;
      
              if (P1.Equals(P4))
                  Console.WriteLine("P1 EQ P4");
              else
                  Console.WriteLine("P1 NEQ P4");
      
              if (P1.Equals(P2))
                  Console.WriteLine("P1 EQ P2");
              else
                  Console.WriteLine("P1 NEQ P2");
      
              if (P1.Equals(P3))
                  Console.WriteLine("P1 EQ P3");
              else
                  Console.WriteLine("P1 NEQ P3");
                  
      		    int X = 5;
      		
      		    Console.WriteLine(object.ReferenceEquals(X, X));
      		}
      }
      
    • Struct Equality →

      • There is 2 ways to check equality all are System.Object Members.
      1. public virtual bool Equals(Object O2) { } → Value Equality
      2. public static bool Equals(Object O1, Object O2) { return O1.Equals(O2); } → Value Equality
      • Operator == → Not Implemented
      • public static bool ReferenceEquals(Object O1, Object O2) { } → Not suitable to use with value type

  • Virtual Methods and Classes →

    class TypeA
    {
        public int A { get; set; }
    
        public TypeA(int _A=0) { A = _A; }
    
        public void StaticallyBindedShow ()
        {
            Console.WriteLine("I am Base");
        }
        ///Dynamically Binded
        internal virtual void DynShow () ///non Private Virtual Method
        {
            Console.WriteLine($"Base {A}");
        }
    }
    
    class TypeB:TypeA
    {
        public int B { get; set; }
        public TypeB(int _A =0 , int _B=0):base(_A)
        {
            B = _B;
        }
    
        internal override void DynShow()
        {
            Console.WriteLine($"Derived {A} {B}");
        }
    
        public new void StaticallyBindedShow() { 
    		    Console.WriteLine("I am Derived"); 
    		}
    }
    
    class TypeC : TypeB
    {
        public int C { get; set; }
    
        public TypeC(int _a=0 , int _b=0 , int _c=0):base(_a , _b)
        {
            C = _c;
        }
    
        internal override void DynShow()
        {
            Console.WriteLine($"Type C {A} {B} {C}");
        }
    }
    
    class TypeD : TypeC
    {
        //internal new void DynShow() 
        /// new statically binded impelementation
        
        /// new dynamically binded impelementation
        internal new virtual void DynShow() 
        {
            Console.WriteLine("Type D");
        }
    }
    class TypeE: TypeD
    {
        ///override on TypeD Implementation
        internal override void DynShow()
        {
            Console.WriteLine("Type E");
        }
    }
    
    class program
    {
    		static void Main(string[] args)
    		{
    			    TypeA BaseRef = new TypeA(1);
              BaseRef.StaticallyBindedShow(); ///Base
              BaseRef.DynShow(); ///Base
    
              TypeB DerivedRef = new TypeB(2, 3);
              DerivedRef.StaticallyBindedShow(); ///Derived
              DerivedRef.DynShow(); ///Derived
    
              BaseRef = new TypeB(4, 5);
              ///Ref to Base = Derived Object
              //BaseRef.A = 6;
              BaseRef.StaticallyBindedShow();///Base
              ///Statically Binded methods (non virtual) 
              //Compiler Bind Call based in Refrence Type not Object Type
              BaseRef.DynShow();///Derived
              ///Dynamically Binded Method , CLR will bind Function 
              //Call based on Object Type in Runtime  
    
              BaseRef = new TypeC(6, 7, 8);
              DerivedRef = new TypeC(9, 10, 11);
    
              BaseRef.DynShow(); ///TypeC
              DerivedRef.DynShow(); ///TypeC
    
              BaseRef = new TypeD();
              BaseRef.DynShow(); ///TypeC
    
              TypeD RefD = new TypeD();
              RefD.DynShow(); ///TypeD
    		}
    }
    

  • Generic Method and Class →
    • Generic Method in non Generic Class →

      • A non-generic class can contain a generic method. This means that the class itself is not parameterized by a type, but it has a method that can work with different types.
      • The generic method can have its own type parameters, distinct from the class type parameters (if any).
      class Helper
      {
          #region Non Generic Swap
          //public static void SWAP ( ref int X , ref int Y)
          //{
          //    int Temp = X;
          //    X = Y;
          //    Y = Temp;
          //}
      
          //public static void SWAP(ref double X, ref double Y)
          //{
          //    double Temp = X;
          //    X = Y;
          //    Y = Temp;
          //}
      
          //public static void SWAP(ref string X, ref string Y)
          //{
          //    string Temp = X;
          //    X = Y;
          //    Y = Temp;
          //} 
          #endregion
      
          ///Generic Method in non Generic Class
          public static void SWAP<T>(ref T X, ref T Y)
          {
              T Temp = X;
              X = Y;
              Y = Temp;
          }
      }
      
      • Main →

        class program
        {
        		static void Main(string[] args)
        		{
        		    #region Generic Method
                int A = 7, B = 3;
        
                Helper.SWAP<int>(ref A, ref B); 
                ///Call Generic Function Explicitly Define T
                //Helper.SWAP(ref A, ref B); ///non Generic Function
        
                Console.WriteLine($"A = {A}");
                Console.WriteLine($"B = {B}");
        
                double D1 = 1.2345, D2 = 1234.5;
        
                Helper.SWAP(ref D1, ref D2); 
                ///In case of Generic Method (Not Generic Class\\struct\\interface)
                ///Compiler can Detect Type PAramter T Type from input Parameteres
        
                Console.WriteLine($"D1 {D1}");
                Console.WriteLine($"D2 {D2}");
        
                String Str1 = "ABC", Str2 = "XYZ";
        
                Helper.SWAP(ref Str1, ref Str2);
        
                Console.WriteLine($"Str1 {Str1}");
                Console.WriteLine($"Str2 {Str2}");
        
                Point P1 = new Point() { X = 10, Y = 20 };
                Point P2 = new Point() { X = 30, Y = 40 };
        
                Helper.SWAP(ref P1, ref P2);
        
                Console.WriteLine($"P1 {P1}");
                Console.WriteLine($"P2 {P2}");
                #endregion
        		}
        	}
        
    • Generic Method in Generic Class →

      • A generic class can also contain generic methods. In this case, the class itself is parameterized by a type, and the generic methods share the same type parameters.
      • The type parameters of the class are available to all its generic methods.
      class Helper<T>
      {
          ///Generic Method in  Generic Class
          public static void SWAP(ref T X, ref T Y)
          {
              T Temp = X;
              X = Y;
              Y = Temp;
          }
      }
      
      • Main →

        class program
        {
        		static void Main(string[] args)
        		{
        		    int A = 7, B = 3;
        	
        	      Helper<int>.SWAP(ref A, ref B); 
        	
        	      Console.WriteLine($"A = {A}");
        	      Console.WriteLine($"B = {B}");
        	
        	      double D1 = 1.2345, D2 = 1234.5;
        	
        	      Helper<double>.SWAP(ref D1, ref D2); 
        	      ///No Type inference for Generic Class
        	
        	      Console.WriteLine($"D1 {D1}");
        	      Console.WriteLine($"D2 {D2}");
        	
        	      String Str1 = "ABC", Str2 = "XYZ";
        	
        	      Helper<string>.SWAP(ref Str1, ref Str2);
        	
        	      Console.WriteLine($"Str1 {Str1}");
        	      Console.WriteLine($"Str2 {Str2}");
        	
        	      Point P1 = new Point() { X = 10, Y = 20 };
        	      Point P2 = new Point() { X = 30, Y = 40 };
        	
        	      Helper<Point>.SWAP(ref P1, ref P2);
        	
        	      Console.WriteLine($"P1 {P1}");
        	      Console.WriteLine($"P2 {P2}");
        		}
        }
        
    • Advantages →

      • Non-Generic Class with Generic Method →
        • Allows you to add generic behavior to a non-generic class without making the entire class generic.
        • Useful for extension methods or utility methods.
      • Generic Class with Generic Method→
        • Provides a consistent type context for both the class and its methods.
        • Useful when you want to ensure that the method operates on the same type as the class.