Reflection Ve IL Emit Kullanarak Basit Object Mapper

2023-05-08

Daha önce çalıştığımız reflection makalelerini kullanarak, .NET 6 ile AutoMapper benzeri bir yapıda mapping uygulamasını reflection ve IL emit kullanarak performanslı olacak şekilde yazalım.

Mapping API’sini oluşturmak için, MyMappingLibrary projesine IMapper adında bir arayüz ve Mapper adında bir sınıf ekleyin.

IMapper.cs

public interface IMapper
{
    TDestination Map<TSource, TDestination>(TSource source);
    void CreateMap<TSource, TDestination>();
}

Mapper.cs

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

public class Mapper : IMapper
{
    private readonly Dictionary<(Type Source, Type Destination), Delegate> _mappingFunctions = new();

    public TDestination Map<TSource, TDestination>(TSource source)
    {
        if (source == null)
        {
            throw new ArgumentNullException(nameof(source));
        }

        var key = (typeof(TSource), typeof(TDestination));

        if (!_mappingFunctions.TryGetValue(key, out var mapFunction))
        {
            throw new InvalidOperationException($"'{typeof(TSource).Name}' ve '{typeof(TDestination).Name}' arasında bir haritalama işlemi tanımlanmadı.");
        }

        return ((Func<TSource, TDestination>)mapFunction)(source);
    }

    public void CreateMap<TSource, TDestination>()
    {
        var sourceType = typeof(TSource);
        var destinationType = typeof(TDestination);
        var dynamicMethod = CreateMapDynamicMethod(sourceType, destinationType);

        var mapFunction = (Func<TSource, TDestination>)dynamicMethod.CreateDelegate(typeof(Func<TSource, TDestination>));
        var key = (sourceType, destinationType);
        _mappingFunctions[key] = mapFunction;
    }

    private DynamicMethod CreateMapDynamicMethod(Type sourceType, Type destinationType)
    {
        var dynamicMethod = new DynamicMethod(
            $"Map_{sourceType.Name}_To_{destinationType.Name}",
            destinationType,
            new[] { sourceType },
            typeof(Mapper),
            true);

        var ilGenerator = dynamicMethod.GetILGenerator();

        // Yeni hedef nesnesi örneği oluştur
        ilGenerator.Emit(OpCodes.Newobj, destinationType.GetConstructor(Type.EmptyTypes));

        // Kaynak ve hedef nesneler arasında eşleşen özelliklerin değerlerini kopyala
        foreach (var sourceProperty in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            var destinationProperty = destinationType.GetProperty(sourceProperty.Name, BindingFlags.Public | BindingFlags.Instance);

            if (
            	destinationProperty != null && destinationProperty.CanWrite && destinationProperty.PropertyType == sourceProperty.PropertyType)
            {
                // Hedef nesneyi yığın üstünde sakla
                ilGenerator.Emit(OpCodes.Dup);

                // Kaynak nesnenin özellik değerini yığın üstünde sakla
                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Call, sourceProperty.GetMethod);

                // Hedef nesnenin özellik değerini ayarla
                ilGenerator.Emit(OpCodes.Call, destinationProperty.SetMethod);
            }
        }

        // Hedef nesneyi geri döndür
        ilGenerator.Emit(OpCodes.Ret);

        return dynamicMethod;
    }
}

Örnek Kullanım

public class Source
{
    public int Id { get; set; }
    public string FullName { get; set; }
}

public class Destination
{
    public int Id { get; set; }
    public string FullName { get; set; }
}

public static void Main()
{
    IMapper mapper = new Mapper();

    // CreateMap metodu ile kaynak ve hedef nesneler arasındaki dönüşümü tanımlayın
    mapper.CreateMap<Source, Destination>();

    // Kaynak nesneyi oluşturun
    var sourceObject = new Source
    {
        Id = 1,
        FullName = "Murat Genç"
    };

    // Haritalama işlemi gerçekleştirin
    var destinationObject = mapper.Map<Source, Destination>(sourceObject);

    // Çıktıyı göster
    Console.WriteLine($"ID: {destinationObject.Id}, FullName: {destinationObject.FullName}");
}

Yukarıdaki örnek, reflection ve IL emit kullanarak performanslı bir şekilde nesneler arasında haritalama yapmaktadır. Bu yaklaşım, haritalama işleminin daha hızlı ve daha verimli olmasını sağlar. Bu sayede, özellikle büyük miktarda veri ile çalışırken önemli performans kazanımları elde edebilirsiniz.



Bu gibi daha fazla gönderi...

SemaphoreSlim Sınıfı: C#'ta Çoklu Görevlere Dayalı Programlama

2023-06-10 | #net #semaphoreslim

Genel Bakış SemaphoreSlim sınıfı, bir veya daha fazla threadin aynı anda belirli bir kaynağı veya işlemi kullanmasını kontrol etmek için C# ‘ta kullanılan bir yapıdır. SemaphoreSlim, aynı anda kaynağa erişebilecek thread sayısını sınırlar. SemaphoreSlim kullanımı, genellikle çok threadli uygulamalarda deadlock durumlarını önlemek ve belirli bir kaynağın aynı anda yalnızca bir veya daha fazla thread tarafından kullanılmasını sağlamak için kullanılır. SemaphoreSlim Kullanımı SemaphoreSlim sınıfı, aşağıdaki gibi kullanılır: SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1); Burada ilk parametre, aynı anda kaç threadin kaynağı kullanabileceğini belirler.

Devamı 


Basit Bir Rest Api Client Geliştirelim 9

2023-05-14 | #diy-rest-api-client #do-it-yourself #net #rest-api

HTTP isteklerini izlemek ve teşhis etmek için daha fazla yetenek ekleyerek, kütüphanemizi daha da geliştirebiliriz. Bu amaçla, isteklerin ve yanıtların bazı temel bilgilerini loga kaydeden bir middleware ekleyelim. Bu özellik, HTTP isteklerinin ve yanıtlarının kaydını tutmak için HttpClient‘in DelegatingHandler sınıfını kullanır. Bu, bir HTTP isteği gönderildiğinde ve bir yanıt alındığında çalışan bir kod parçasıdır. Bu durumda, HTTP isteklerinin ve yanıtlarının bazı temel bilgilerini loga kaydeder. Aşağıda, bu özelliği eklemek için gereken kod parçacığı bulunmaktadır:

Devamı 


Basit Bir Rest Api Client Geliştirelim 8

2023-05-12 | #diy-rest-api-client #do-it-yourself #net #rest-api

Bu noktada, geliştirmemiz gereken bir diğer önemli konu da güvenlikle ilgili olabilir. Özellikle, API çağrıları genellikle belirli bir kimlik doğrulama yöntemi gerektirir. Bunu sağlamak için, HTTP istemcimizi çok kullanılan iki kimlik doğrulama yöntemiyle, yani Basic Authentication ve Bearer (Token) Authentication ile uyumlu hale getirebiliriz. Bu amaçla, istemcimize iki yeni metot ekleyelim: public void SetBasicAuthentication(string username, string password) { var basicAuthValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")); SetDefaultHeader("Authorization", $"Basic {basicAuthValue}"); } public void SetBearerToken(string token) { SetDefaultHeader("Authorization", $"Bearer {token}"); } Bu metodlar, Authorization başlığını ayarlar, böylece her HTTP talebi kimlik doğrulama bilgilerini içerir.

Devamı 