.NET Core 3.0 ile Gelen Yenilikler ve VS2019 Preview / What’s Coming With .NET Core 3.0

Merhaba Yazılım Meraklıları,

Bu yazıda .NET Core 3.0 ile gelen yenilikleri inceleyeceğiz ve genel bir inceleme yapacağız. Aynı zamanda C# 8.0 (preview) ile gelen yeniliklere ve kullanımlara da bakıyor olacağız.

Hemen hemen tüm örneklemeler MS Windows OS üzerinden anlatılmıştır.

Gerekli kurulumlar ile Başlayalım

– Öncelikle bu özelikleri kullanabilmek için Visual Studio 2019 ‘a (yazı tarihiyle preview version) ihtiyacınız olacak.

Visual studio 2019 download

VisualStudio2019 Preview Installing

Şimdilik sadece aşağıdaki workload’ları yükleyeceğim.

 

– Ardından linkten .Net Core 3.0 ‘ı indirip kurun.
.Net Core 3.0 SDK Installing

– Son olarak hazır kurulumlara ısınmışken şuradan .Net Framework 4.8 (early access) de indirip kurun.

Artık latest version IDE, Framework ve SDK’lara sahibiz. Bu yazının tarihi itibariyle tabi ki = )
O halde bizim için yeni oynayacak hangi oyuncakları koymuşlar incelemeye geçebiliriz.

WPF (Windows Presentation Foundation), Windows Forms -> Windows Desktop

.Net core 3.0 ile en çok göze çarpan yenilik WinDesktop tarafında gözüküyor.
Artık WPF ve WinForms applicationlarını .Net Core bu sürümü ile destekliyor. Bu da haliyle en major feature yapıyor bunu.

VS2019 üzerinden birer WPF ve WinForm application oluşturalım.

  • WPF Application

Tüm adımları aşağıdaki ekran görüntülerinde görebilirsiniz.
VS2019CreateProjectScreen

Yukarıdaki adımlarda sırasıyla Project Type’ımızı seçtik > ProjectName ve Location folder gibi bilgileri set edip > Basit bir text change ile Execute ettik.

Bu işlemleri komut satırı ile de yapabilirsiniz. Onun da kodu aşağıdadır.

dotnet new wpf -o wpfDotNetCore3Dot0Exm
  • Windows Form

Tüm adımları aşağıdaki ekran görüntülerinde görebilirsiniz.

Yukarıdaki adımlarda sırasıyla Project Type’ımızı seçtik > ProjectName ve Location folder gibi bilgileri set edip > Basit bir text change ile Execute ettik.

Bu işlemleri aşağıdaki komut satırı ile de yapabilirsiniz.

dotnet new winforms -o wfDotNetCore3Dot0Exm

ASP.Net Core Web Applications

  • Razor Componentler – UI.
  • gRPC Apps
  • Web Applicationlarımız için ekstra bir efor sarfetmemize gerek kalmadan Local’de HTTPS desteği veriyor.

ve daha saymadığım bir çok bir çok ince detay var. Derinlemesine girip bu makalede saatlerinizi almamak için başlıklar üzerinden hoşuma gidenlere değiniyorum.

Örneğin Razor Componentler’e ufaktan girebiliriz.
.Net Developer olarak UI’da çok efektif işler çıkarabileceğiniz bir template olmuş. DI tarafı dikkatimi çekti, UI’a Classlarınızı inject edebiliyorsunuz. Basit bir uygulama ile inceleyelim.

Create Razor Component Application

Yukarıdaki ekran görüntüsündeki sağ tarafta olan “Advanced” bölümünün altında “Configure for HTTPS” i seçip daha sonra CREATE yapın.

Razor Components Application’ımız oluştu hemen F5 ile çalıştırırsak aşağıdaki gibi HTTPS ile geldiğini göreceğiz.

Not: İlk defa çalıştırınlar, HTTPS için bir uyarı penceresi alacaklar. Onu onaylayıp devam edin.

Biraz code tarafını inceleyelim.

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc()
                .AddNewtonsoftJson();

            services.AddRazorComponents();

            services.AddSingleton<WeatherForecastService>();
        }

Eğer bu projede “WeatherForecastService” ini incelersek. Startup.cs içerisinde yukarıda gibi “WeatherForecastService” i Singleton olarak set edilmiş ve aşağıdaki kod parçacağına baktığınızda ise “UI” olan FetchData.razor içerisinde nasıl inject edilip, nasıl kullanıldığını görüyorsunuz.

@page "/fetchdata"
@using WARazorComponents.Services
@inject WeatherForecastService ForecastService

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from a service.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@functions {
    WeatherForecast[] forecasts;

    protected override async Task OnInitAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
}

Ayrıca örnek olarak oluşturduğumuz razor component web application’ın içerisindeki diğer page lerdeki kod yazımlarına da bakarsanız sanırım buna JavaScript duyarlıklı C# diyebiliriz. =)

.Net Core 3.0 ile Yürütülebilir Uygulamalar (Executable Applications)

Herhangi bir Tool kullanmadan direkt Command Prompt üzerinden uygulama oluşturup execute edebileceğiniz code lineları aşağıda paylaşıyorum. Hem Window için hem de Linux için.

Windows için / For Windows :

/*Komutları sırasıyla teker teker çalıştırın!*/
dotnet new console -o consoleDotNetCore3Dot0
cd consoleDotNetCore3Dot0
dotnet build
cd binDebugnetcoreapp3.0
dir /b     /*Bunu kullanmadan direkt aşağıdaki satırı da çalıştırabilirsiniz*/
consoleDotNetCore3Dot0.exe

Linux için / For Linux :

/*Komutları sırasıyla çalıştırın*/
root@123456789:/consoleDotNetCore3Dot0# dotnet build
root@123456789:/consoleDotNetCore3Dot0# cd bin/Debug/netcoreapp3.0/
root@123456789:/consoleDotNetCore3Dot0/bin/Debug/netcoreapp3.0# ls  /*Bunu çalıştırmaya bilirsiniz, görmeniz içindir.*/
root@123456789:/consoleDotNetCore3Dot0/bin/Debug/netcoreapp3.0# dotnet consoleDotNetCore3Dot0.dll

Ranges & Index

Belki de en çok hoşuma giden yeniliklerden birisi bu oldu.
Basitçe tanımlayacak olur ise bir dizi için tanımlayacağımız startIndex ve endIndex değişkenleriyle, ilgili dizi içerisinde bu indexlerimizin aralığında kalan itemları alabilmemizi sağlıyor.
endIndex’i için “^” prefixi kullanılıyor ve index aralığını belirtmek için ise “..” kullanılmaktadır.
Direkt aşağıdaki kod parçağını çalıştırıp inceleyebilirsiniz.

static void Main(string[] args)
{
    Index startIndex = 1;
    Index endIndex = ^3;
    string[] charSet = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
    var indexRange = charSet[startIndex..endIndex]; //"b".."w"
    var indexRangeResult = String.Join(",", indexRange.Select(s => s));
    Console.WriteLine(indexRangeResult);
    Console.ReadKey();
}

Async Streams

IEnumerable<> interface inin async kullanımı için “IAsyncEnumerable” bulunmaktadır. Yani Task<> kullanmadan async bir method oluşturabiliyoruz.  Bu oluşturduğumuz methodun listesini de “foreach” döngüsünün başına “await” getirerek kullanabiliyoruz. Aşağıda api aracılığıyla döviz verilerini getiren örnek kod parçaları üzerine uyguladım.

public async IAsyncEnumerable<string> DovizDataAsync()
{
    await foreach (var item in GetAsyncDovizData())
        yield return string.Join(", ", item.name, item.code, item.sellPrice);
}

public async IAsyncEnumerable<DovizDto> GetAsyncDovizData()
{
    var response = new WebClient().DownloadString("https://api.canlidoviz.com/web/items?marketId=1&type=0");
    var deObject = JsonConvert.DeserializeObject<List<DovizDto>>(response);
    foreach (var item in deObject)
        yield return item;
}


//Data Transfer Object
 public class DovizDto
{
    public string name { get; set; }
    public string code { get; set; }
    public float todayLowestBuyPrice { get; set; }
    public float todayHighestBuyPrice { get; set; }
    public float todayLowestSellPrice { get; set; }
    public float todayHighestSellPrice { get; set; }
    public float yesterdayClosingBuyPrice { get; set; }
    public float yesterdayClosingSellPrice { get; set; }
    public float buyPrice { get; set; }
    public float sellPrice { get; set; }
    public float dailyChange { get; set; }
    public float dailyChangePercentage { get; set; }
    public string lastUpdateDate { get; set; }
}

 

Son olarak herşeyi toparlarsak ve değinmediğimiz diğer özellikleri de ekleyecek olursak.

  • Visual Studio’ya farklı bir hava kazandırılmış. Beğenilir veya beğenilmez göreceğiz.
  • WinDesktop tarafına WPF ve WinForm Applicationlar getirildi. Aynı zamanda EF de destekleniyor.
  • Razor Componentler ile Server-Side & Client-Side mantığı artık bir .Net developer için aynı diyebiliriz.
  • IOT desteği
  • Linux üzerinde TLS 1.3 ve OpenSSL 1.1.1 destekleniyor
  • WinClientOS: Win7 ve üzeri için destekleniyor.
  • WinServerOS: 2012 R2 SP1 ve üzeri için destekleniyor.
  • .csproj içerisine <NullableContextOptions>enable</NullableContextOptions>” tagini ekleyerek null check kullanımı rahatlığından faydalanabilirsiniz.
  • Cryptography (Buna farklı bir yazıda değinebiliriz.)
  • JsonReader (Buna da farklı bir yazıda benchmark yaparak bakacağız. Linkini buraya koyarım.)
  • C# 8 özellikleri .Net Framework 4.8 ile kullanılabiliyor.

Bir başka yenilikte görüşmek üzere.

.Net Core ile Protobuf Kullanımı ve JSON Performans Karşılaştırması

Merhabalar,

Öncelikle eğer kemerlerinizi bağlamadıysanız hemen bağlayın, çünkü birazdan Protobuf-net ile uçuşa geçeceğiz. Nasıl mı?

Şöyle ki kodlara girmeden önce kısaca Protocol Buffers’dan bahsedelim.

Google tarafından geliştirilmiştir ve amacı ise yapılandırdığınız dataların serileştirilmesini(serialization) sağlamaktır.

Örnek olarak herkes tarafından bilinen XML Format’ını düşünebilirsiniz. Bu örnekteki handikap şudur. XML DOM’ları içerisinde gezinmek kompleksdir ve Serialize/Deserialize işlemlerinin de maliyeti biraz yüksektir. Buna alternatif olarak yine tüm geliştiriciler tarafından bilinen ve sektörde kabul görmüş JSON Format karşımıza çıkıyor. Bunların detaylarına girmeyeceğim. Çünkü asıl konumuzdan uzaklaşmak istemiyorum. Protobuf bize bu serileştirme işlemlerini birçok formata göre çok daha hızlı bir şekilde gerçekleştiriyor.

Şimdi, Protobuf’ın nasıl kullanıldığına ve JSON’a göre nasıl bir performans gösterdiğine bakacağımız uygulamamıza geçelim.

  • İlk olarak bir .Net Core Console Application oluşturun.
  • Ardından Package Manager Console’u açıp şu komutları çalıştırın.
 Install-Package protobuf-net
Install-Package Newtonsoft.json



 

Protobuf Contract Tanımlamaları

Contract based çalışan bir yapısı var ve ilgili model classlarımıza attribute olarak tek seferlik tanımlayıp kullanıyoruz.  Örnek için kendime şu contractları oluşturdum. Siz isterseniz farklı bir senaryo üretebilirsiniz.

using ProtoBuf;
using System;

namespace ProtobufnetVSNewtonsoftjson.Contracts
{
    [ProtoContract]
    [ProtoInclude(3, typeof(Order))]
    public class BaseContract
    {
        [ProtoMember(1)]
        public int CreatedBy { get; set; }
        [ProtoMember(2)]
        public DateTime CreatedDate { get; set; }
    }
}
namespace ProtobufnetVSNewtonsoftjson.Contracts
{
    public enum AddressType
    {
        Billing = 1,
        Delivery = 2
    }
}
using ProtoBuf;

namespace ProtobufnetVSNewtonsoftjson.Contracts
{
    [ProtoContract]
    public class Address
    {
        [ProtoMember(1)]
        public string City { get; set; }
        [ProtoMember(2)]
        public string Line1 { get; set; }
        [ProtoMember(3)]
        public string Line2 { get; set; }
        [ProtoMember(4)]
        public AddressType Type { get; set; }
    }
}
using ProtoBuf;
using System.Collections.Generic;

namespace ProtobufnetVSNewtonsoftjson.Contracts
{
    [ProtoContract]
    public class Customer
    {
        [ProtoMember(1)]
        public string FullName { get; set; }
        [ProtoMember(2)]
        public string Phone { get; set; }
        [ProtoMember(3)]
        public List<Address> Addresses { get; set; }
    }
}
using ProtoBuf;

namespace ProtobufnetVSNewtonsoftjson.Contracts
{
    [ProtoContract]
    public class Product
    {
        [ProtoMember(1)]
        public string ProductSKU { get; set; }
        [ProtoMember(2)]
        public string ProductName { get; set; }
        [ProtoMember(3)]
        public int Quantity { get; set; }
        [ProtoMember(4)]
        public decimal Price { get; set; }
    }
}
using ProtoBuf;
using System;
using System.Collections.Generic;

namespace ProtobufnetVSNewtonsoftjson.Contracts
{
    [ProtoContract]
    public class Order : BaseContract
    {
        [ProtoMember(1)]
        public string OrderNumber { get; set; }
        [ProtoMember(2)]
        public DateTime OrderDate { get; set; }
        [ProtoMember(3)]
        public decimal TotalPrice { get; set; }
        [ProtoMember(4)]
        public List<Product> Products { get; set; }
        [ProtoMember(5)]
        public Customer CustomerInfo { get; set; }
    }
}

Yukarıdaki Contract tanımlamalarında inheritance ve diğer caseler için kullanımlarını görebilirsiniz. Simple bir yapıya sahip. Her member Unique’dir.
Örnekte “ProtoContract, ProtoInclude ve ProtoMember(N)” attribute’leri kullanılmıştır.

ProtoInclude: Inheritance kullanılacaksa bu etiket eklenir.

ProtoContract: Object modelinin en tepesine eklenen etiketdir.

ProtoMember(N): Object modelindeki memberlara uygulanır ve N(=1,=2=3, vb.) değeri unique olmalıdır. Aksi halde runtimeda hata fırlatır.

  • Oluşturduğumuz contractlar ile program.cs->main method içerisine inMemory data ekliyoruz.
        #region inMemoryData
            var data = new Order
            {
                CreatedBy = 1,
                CreatedDate = DateTime.Now,
                OrderDate = DateTime.Now,
                OrderNumber = "MSTF123456789",
                TotalPrice = 150,
                Products = new List<Product>{
                                              new Product {
                                                            ProductName = "Test Product 1" ,
                                                            ProductSKU = "TP123456",
                                                            Quantity = 2,
                                                            Price = 25
                                                          },
                                              new Product {
                                                            ProductName = "Test Product 2" ,
                                                            ProductSKU = "TP123457",
                                                            Quantity = 1,
                                                            Price = 100
                                                          }
                                            },
                CustomerInfo = new Customer
                {
                    FullName = "Mustafa KOÇ",
                    Phone = "5551112233",
                    Addresses = new List<Address> {
                                                   new Address {
                                                                   City ="İstanbul",
                                                                   Line1 = "Maslak Mh.",
                                                                   Line2 = "Şişli",
                                                                   Type = AddressType.Delivery
                                                                },
                                                   new Address {
                                                                   City ="İstanbul",
                                                                   Line1 = "Maslak Mh.",
                                                                   Line2 = "Şişli",
                                                                   Type = AddressType.Billing
                                                               }
                                                  }
                }
            };
        #endregion
  • Hemen ardına aşağıdaki kod bloğunu ekleyin.
                byte[] serializedData;
                Order deserializedOrder = new Order();
    
                #region Protobuf-net
                var watchProtoBuf = System.Diagnostics.Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                {
                    using (var mStream = new MemoryStream())
                    {
                        ProtoBuf.Serializer.Serialize(mStream, data);
                        serializedData = mStream.ToArray();
                    }
                    using (var mStream = new MemoryStream(serializedData))
                    {
                        deserializedOrder = ProtoBuf.Serializer.Deserialize<Order>(mStream);
                    }
                }
                watchProtoBuf.Stop();
                var elapsedMsProtoBuf = watchProtoBuf.ElapsedMilliseconds;
                Console.WriteLine($"ProtoBuf-net 1.000.000 row data Serialize/Deserialize ExecutionTime(ms): {elapsedMsProtoBuf}");
                #endregion
    
                #region  Newtonsoft.Json
                string jsonSerializedData = string.Empty;
                var watchJson = System.Diagnostics.Stopwatch.StartNew();
                for (int i = 0; i < 1000000; i++)
                {
                    jsonSerializedData = JsonConvert.SerializeObject(data);
                    deserializedOrder = JsonConvert.DeserializeObject<Order>(jsonSerializedData);
                }
                watchJson.Stop();
                var elapsedMsJson = watchJson.ElapsedMilliseconds;
                Console.WriteLine($"Newtonsoft.Json 1.000.000 row data Serialize/Deserialize ExecutionTime(ms): {elapsedMsJson}");
                #endregion

    Yukarıdaki kod bloğunda “Protobuf-net” c# dili ile kullanımı #region etiketleri içerisinde belirtilmiştir. Hemen altında ise Json kullanım örneği yine #region etiketleri arasında gösterilmiştir.

    ProtoBuf.Serializer.Serialize(mStream, data) satırında inMemory datasını stream ediyoruz ve sonrasında byte dizisine dönüştürüyoruz. Bu dönüşüp sonucu bize serialized datayı veriyor. Datayı deserialize etmek için ise serialized datayı stream edip ProtoBuf.Serializer.Deserialize<T>(mStream) methodunu kullanıyoruz. Burada T generic dönüşümün yapılacağı tür, mStream ise deserialize edilecek data.

Şimdi çalıştırıp performans analizini gözlemleyebiliriz.

Senaryo: Serialize/Deserialize for 1.000.000 object
Formatlar: Protobuf, Json

Result:

ProtoBuf-net 1.000.000 row data Serialize/Deserialize ExecutionTime(ms): 9715
Newtonsoft.Json 1.000.000 row data Serialize/Deserialize ExecutionTime(ms): 25840

Resultımızı görselleştirirsek performans farkını daha iyi görebiliriz.

 

Application Open Source Code: https://github.com/mustafa-koc/ProtobufnetVSNewtonsoftjson

CSharp – Nesne Yönelimli Programlama (OOP) Nedir – Tüm Detaylarıyla

Bir önceki yazımızda OOP hakkında genel fikir verici şeylerden bahsedip aslında neye hizmet ettiğini, ne yaptığını ve ne için ortaya çıktığı gibi soruları cevaplandırmış olduk. Şimdi ise nesne yönelimli programlamanın detaylarına ineceğiz. 5 ana başlık altında anlatmaya çalışacağım.

1. Classes & Object (Sınıflar ve Nesneler)

Gerçek hayatta sorun olarak baz alınan modellemeyi ifade eder. Bu sınıflardan aldığımız instance’lar ile de objelerimizi elde ederiz.
Sınıf oluşturma;

class OrnekSinif 
{  
}  

Ayrıca class yerine struct terimi ile de böyle bir örnekleme yapabiliriz. Struct ise daha küçük kapsamlı bir öğeyi betimlemek istediğimizde kullanabiliriz. Örneğin bir kitap veya stok özellikleri gibi bilgiler için kullanılabilir. Büyük hacimler için tercih edilmez.

  • Encapsulation , Properties , Fields (Kapsülleme)

Encapsulation, bir fielda direk erişimi engelleyerek değimi yerindeyse onu sarmallar ve girdi çıktıları kontrol altına alır.

class OrnekSinif 
{  
    private string ornekField;
}
class OrnekSinif 
{  
    //Okuma veya Atama işlemlerinde herhangi bir aksiyon almak istediğinizde get/set'leri kullanırız.
    public string OrnekProperty { get; set; } 
}

Son olarak kapsülleme örneği ise aşağıdaki şekildedir.

class OrnekSinif 
{  
    private string _ornekField;
    public string OrnekProperty
    {  
        // Field'daki data döndürülüyor. 
        get { return _ornekField; }  
        // Field'a data set ediliyor. 
        set { _ornekField = value; }  
    }
}
  • Methods, Overload Methods

Metodlar, bir sınıfa veya nesneye bağlı olarak çalışıp ilgili eylemleri yerine getirirler. Method oluşturma şablonu şu şekildedir:
“Erişim belirleyicisi/dönüş tipi/Metod Adı/(optinal) Parametreler”.
Örnek method oluşturma.

class OrnekSinif 
{
    //Parametresiz
    int OrnekMethod()
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
    
    //Parametreli
    int OrnekMethod(int sayi)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
}

Aynı method isminde ve farklı parametreler ile oluşturduğumuz methodlara ise Overload Method denir.

class OrnekSinif 
{
    int OrnekMethod(int sayi)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı
    }
    
    int OrnekMethod(string a)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
    
    int OrnekMethod(int sayi, string a)
    {  
        // kod parçacığı 
        // ... 
        // kod parçacığı 
    }
}

Extension Methodlar ve daha fazla method detayını farklı başlıklar altında değineceğiz.

  • Constructor Methods (Yapılandırıcı/Kurucu Method)

Class’dan bir instance oluşturulurken ilk olarak Constructor tetiklenir ve çalışır. Bu instance’a ilişkin olarak alınması gereken aksiyonlar da burada yer alır. Ayrıca constructor methodlar overload da edilebilir.

public OrnekSinif 
{  
    public OrnekSinif()
    {  
        // ctor kod parçacığı 
        // ... 
        // ctor kod parçacığı 
    }

    //ctor overload
    public OrnekSinif(string a, string b)
    {  
        // ctor kod parçacığı 
        // ... 
        // ctor kod parçacığı 
    }
}
  • Finalizers (Sonlandırıcılar)

.Net Framework bu işlemi hali hazırda otomatik olarak yapıyor. Nesnelere destruct uygular, yani yıkar. Bellek yönetimi yapar. Fakat otomatik olarak yapılamayan nesneleriniz var ise bunların destruct yönetimini sizin yapmanız gerekir. Bu başlık kendi başına bir konu aslında GC namespace’i altında inceleyeceğiz.

  • Events (Olaylar)

Nesnelerimiz üzerindeki changed, click gibi olaylarda almak istediğimiz aksiyonlarımızda devreye girer. Bu başlık altında “Delegate”, “+=”, “Invoke” ifadeleri ile çokça karşılaşacaksınız.

  • Nested Classes (İç İçe Sınıflar)

Bir sınıf içerisine tanımlanmış başka bir sınıfı ifade eder. Basitçe şöyle tanımlanır:

class KapsayiciSinif  
{  
    class IcSinif  
    {  
        // kod parçacığı  
    }  
}
KapsayiciSinif.IcSinif icObje = new KapsayiciSinif.IcSinif()
  • Access Modifiers (Erişim Belirleyicileri)

Bir sınıf veya sınıf üyelerinin hangi erişim düzeyinde olacağını belirler.

public :
Bulunduğu class ve dışarıdan tam erişim.

private :
Dışarıdan hiçbir şekilde erişilemez. Sadece bulunduğu class içerisinde erişilebilir.

protected 
:
Bulunduğu class’dan ve bulunduğu class’da türetilen class’lardan erişilebilir.

internal 
:
Bulunduğu assembly(dll veya exe) içerisinden erişilebilir.

protected internal 
:
proctected özelliklerine tamamen sahip ve ayrıca bulunduğu assembly(dll veya exe) içerisinde olmasa dahi tanımlandığı class’dan türetilen tüm class’lardan erişilebilir.

private protected :
private özelliklerini aynen taşır. Artı olarak bulunduğu class’dan türetilen tüm class’lardan da erişilebilir.

  • Instantiating Classes

Sınıflardan obje oluşturmak instance oluşturmak gerekir.

class OrnekSinif 
{  
    public string Property1 { get; set; } 
    public string Property2 { get; set; }

    public int PlusOne(int a)
    {  
        return a + 1;
    }
}

Şimdi bu sınıftan bir instance alma ve kullanma şekillerine bakalım.

OrnekSinif ornekSinif = new OrnekSinif();//Instance oluşturduk.
ornekSinif.Property1 = "Hello";

OrnekSinif ornekSinif2 = new OrnekSinif{ Property1 = "Hello", Property2 = "World" };
//Property Set ederek instance oluşturduk.
  • Static Classes & Members (Statik Sınıflar)

Statik sözcüğü, sınıflar ve üyeleri için herhangi bir instance işlemine gerek duyulmadan direk erişilebilmesini sağlar.

public static class OrnekSinif 
{  
    public static string Property1 = "Hello";
    public static string Property2 = "World";

    public static int PlusOne(int a)
    {  
        return a + 1;
    }
}

kullanımı

//Herhangi bir instance oluşturmadan direk erişebildik.
string metin = OrnekSinif.Property1 + " " + OrnekSinif.Property2;
int sayi = OrnekSinif.PlusOne(1);
  • Anonymous Types (Anonim Tipler)

Herhangi bir veri türü veya class belirtmeksizin oluşturulur. Bu işlemi verilen sınıf veya veri türüne göre sistem otomatik olarak yapar. Fakat bizim bir tür belirtmemize gerek kalmaz tanımlama yaparken.

var obj = new { A = "Hello", B = "World" };

2. Inheritance (Kalıtım, Miras Alma, Devralma)

Bir sınıfın özelliklerinin kalıtım yolu ile başka bir sınıfa aktarılmasıdır.

Bir class yalnızca bir class’ı miras alabilir.

class A //Base class
{

}

class C
{

}

//B class'ı A class'ı özelliklerini devralıyor.
class B:A
{

}


//Bir de yanlış kullanımını gösterelim
class B : A, C // Böyle bir kullanım yoktur. Aynı anda 2 farklı class bu işlem için kullanılamaz.
{

}

NOT: Bu noktada iki farklı konu karşımıza çıkıyor. Birincisi “sealed class” , ikincisi ise “abstract class” kavramlarıdır.

sealed class: sealed olarak tanımlanan bir class, başka bir class’a inheritance(kalıtım, miras alma, devralma) için kullanılamaz. Sadece ilgili bussines’ı veya görevi yerine getirir. Bu sınıfta bulunan herhangi bir method veya member’ın ezilmesini istemeyiz.
abstract class: abstract şekilde tanımladığımız classları base olarak kullanırız. Yani “bir varlığın en temel özelliklerini en ilkel şekilde barındırır” diyebiliriz. Abstract class’lardan instance oluşturulamaz. İçerisine kod yazılabilir. Private olarak tanımlanamazlar. Interface’lerden ayrılan yanlarından birisi de budur.  Ayrıca belirlediğimiz bu temel özellikleri türetilen sınıfta override edip, türetilen class’a uygun şekil almasını sağlayabiliriz.

public sealed class A { } //Sealed class tanımlama

public abstract class B { } //Abstract class tanımlama
  • Overriding (ezme, geçersiz kılma, çiğnemek)

Base class’dan alınan default özellikleri, türetilen sınıfa göre değiştirmek/geçersiz kılmak istiyorsak bu işlemi uygularız.

C# Modifiers: virtual, override, abstract, new Modifier

virtual: Türetilen sınıfta override edilebilmesini sağlar.
override: Türeyen sınıfta override eder.
abstract: Türeyen sınıfta override etmek zorunludur.
new: Türetilen sınıftan devralınan member’ı gizler.

public class BaseClass
{
    public virtual void OzellikYazdir()
    {
        Console.WriteLine("Hello");
    }
}

public sealed Example:BaseClass
{
    public override void OzellikYazdir()
    {
        Console.WriteLine("Hello World!");
    }
}

3. Interfaces (Arabirimler)

Sınıfların kullanacağı özelliklerin sözleşmesinin yapıldığı ara birimlerdir. Bu arabirimleri referans alan tüm class’lar, ilgili sözleşmedeki tüm member’ları kullanmak zorundadır. Bir class birden fazla interface alabilir.

public interface IExample  
{  
    void OrnekMethod();
}


class OrnekSinif : IExample  
{  
    void OrnekMethod()  
    {  
        // kod
        // ...
        // kod
    }  
} 
public interface IEkle
{  
    void Ekle();  
}

public interface ISil
{  
    void Sil();  
}

public interface IDuzenle
{  
    void Duzenle();  
}

public interface IListele
{  
    void Listele();  
}


public class OrnekSinif : IEkle, ISil, IDuzenle, IListele
{  
    void Ekle()  
    {  
        // kod
        // ...
        // kod
    }
    
    void Sil()  
    {  
        // kod
        // ...
        // kod
    }
    
    void Duzenle()  
    {  
        // kod
        // ...
        // kod
    }
    
    void Listele()  
    {  
        // kod
        // ...
        // kod
    }
} 

4. Generics

Generic olarak oluşturulacak öğe, hangi türde oluşturulması isteniyorsa o türü parametre olarak alır ve o işlemi gerçekleştirir. Bize şunu sağlar: Tek seferde yazılan bir işlevi farklı obje türleri için de işlevsel hale getirebilme imkanı verir. Yani birçok iş için bir kere efor harcanır. Gereksiz kod tekrarının önüne geçer.

Generic Sınıf Tanımlama ve Kullanımı

public class ExampleGeneric<T>//T tipi alınıyor.
{
    public T Insert(T model)
    {
        //Insert işlemi
        //....
        return model;
    }
}
ExampleGeneric<TypeName> exam = new ExampleGeneric<TypeName>();

var resultItem = exam.Insert(new TypeName{ /*Properties*/ });

5. Delegates (Temsilciler)

Temsilciler (delegate), bir “t” zamanında, bir “y” aksiyonu dolayısıyla tetiklenmesini istediğimiz aksiyonları almamızı sağlar. Yani örnek vermek gerekecek olursak bir ekranda bir butona bastıktan sonra bu işlemin daha başka methodları da tetiklemesini istiyorsak bu yöntemi kullanabiliriz. Yordam saklamaya yarar. Parametre alması gereken durumlarda parametre de verilebiliyor. Ufak bir örnek kod yazalım.

//------------------------------------------
public delegate void ornekDelegate();

public void Method1()
{
    Console.WriteLine("Method 1");
}
public void Method2()
{
    Console.WriteLine("Method 2");
}
public void Method3
{
    Console.WriteLine("Method 3");
}
//------------------------------------------

//Kullanımı
ornekDelegate ornek = new ornekDelegate(Method1);
ornek += new testDelegate(Method2);
ornek += new testDelegate(Method3);
ornek();//Burası run edildiği zaman ekrana "Method 1", "Method 2" ve "Method 3" basacak.

Bu ve diğer tüm başlıklar hakkında talep ederseniz daha derinlemesine işleyebiliriz. Yazıyı çok uzatmak istemedim. Çünkü herşeyi tek bir başlık altında anlatmak çok uzun sürer.
Sorularınız veya değinmemi istediğiniz konular var ise sorabilirsiniz. Zaman bulabildikçe yanıt vermeye çalışacağım.