11 Haziran 2019 Salı

Partial Class

Giriş
.Net ile gelen partial class özelliği iki şeye yarıyor.

1. Kodun Farklı Dosyalara Bölünmesi
Açıklaması şöyle.
When working on large projects, spreading a class over separate files enables multiple programmers to work on it at the same time.
God Object
God object şeklindeki çok büyük sınıfları okunabilirlik için daha küçük dosyalara bölmek için de kullanıldığı belirtilmiş. Mesela büyük sorguların başka bir sınıfta tanımlanması iyi bir örnek olabilir. Dolayısıyla partial sınıfı bir çeşit region'a dönüşüyor.

2.  Kod Üretilmesi
Klasik nesne türetme (inheritance) yapmaya gerek kalmadan bir sınıfın daha ileri bir zamanda yazılma imkanının olması. Bir nevi "abstract metod" yazmaya benziyor ancak daha esnek bir yapı çünkü işin içine nesne türetme girmiyor.

Örnek - Kodun Farklı Dosyalara Bölünmesi
Elimizde farklı dosyalarda olan şöyle bir kod olsun.
public partial class Foo //Foo.cs
{
  public void PrintMessage1()
  {
    Console.WriteLine("Foo1");
  }  
}

public partial class Foo //Foo1.cs
{
  public void PrintMessage2()
  {
    Console.WriteLine("Foo2");
  }
}

public partial class Foo //Foo3.cs
{
  public void PrintMessage3()
  {
    Console.WriteLine("Foo3");
  }
}
Şöyle yaparız.
public static void Main()
{
  Foo foo = new Foo();
  foo.PrintMessage1();
  foo.PrintMessage2();
  foo.PrintMessage3();
}
Örnek - Sınıfın İskeletinin Tanımlanması ve Kodun Üretimesi
Aşağıda bu işi gösteren bir örnek var.
Partial Class kullanımı genellikle üretilen (generated) kod için tercih ediliyor.

Diğer

Access Modifier
Partial class tanımlamalarından hepsine aynı acces modifier tanımlamasını yapmak gerekir.
All the parts must have the same accessibility, such as public, private, and so on.
Eğer sadece bir tanesine access modifier tanımlanmış ise diğeri de aynı özelliğe sahip oluyor.

Örnek
Şöyle yaparız..
public partial class Form1 : Form
ve
partial class Form1


19 Mayıs 2019 Pazar

Operator == Overloading

Giriş
Bu tür kodları hiç sevmiyorum. Dili ve kodu çok karmaşık hale getiriyor.

Örnek
Thing isimli sınıfımız ve içinde bir Id alanı olsun. Sınıfın için operator == ve operator != metodunu eklemek için şöyle yaparız.
public static bool operator ==(Thing self, Thing other)
{
  return !ReferenceEquals(self, null) && 
         !ReferenceEquals(other, null) && 
         self.Id == other.Id;
}

public static bool operator !=(Thing self, Thing other)
{
  return !(self == other);
}
Örnek
Şöyle yaparız.
using System;

class Test
{
  // All this code is awful. PURELY FOR DEMONSTRATION PURPOSES.
  public static bool operator==(Test lhs, Test rhs) => true;
  public static bool operator!=(Test lhs, Test rhs) => true;        
  public override bool Equals(object other) => true;
  public override int GetHashCode() => 0;

  static void Main()
  {
    Test a = null;
    Test b = null;
    Console.WriteLine(a != b);    // True
    Console.WriteLine(!(a == b)); // False
  }    
}
Örnek
operator == için kısıt verebiliriz. T için SillyClass kısıtı vermek için şöyle yaparız.
class SillyClass
{
    public static string operator ==(SillyClass x, SillyClass y) => "equal";
    public static string operator !=(SillyClass x, SillyClass y) => "not equal";
}

class SillySubclass : SillyClass
{
    public static string operator ==(SillySubclass x, SillySubclass y) => "sillier";
    public static string operator !=(SillySubclass x, SillySubclass y) => "very silly";
}

var x = new SillySubclass();
var y = new SillySubclass();
OpTest(x, y);


static void OpTest<T>(T x, T y) where T : SillyClass
{
  Console.WriteLine(x == y);
  Console.WriteLine(x != y);
}
String Sınıfı
String için operator == overload edilmiştir ve reference comparison yerine denklik karşılaştırması yapar. Şöyle yaparız.
string x = "test";
string y = new string(x.ToCharArray());
Console.WriteLine(x == y); // Use string overload, checks for equality, result = true
Console.WriteLine(x.Equals(y)); // Use overridden Equals method, result = true
Console.WriteLine(ReferenceEquals(x, y)); // False because they're different objects
Console.WriteLine((object) x == (object) y); // Reference comparison again- result = false