最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用C#表達式樹實現(xiàn)對象的深克隆(實例詳解)

 更新時間:2024年05月15日 09:33:38   作者:a1010  
C# 的表達式樹提供了一個強大的機制,可以將代碼以數(shù)據(jù)結(jié)構(gòu)的形式表示出來,使得代碼可以在運行時進行檢查、修改或執(zhí)行,這為動態(tài)查詢生成、代碼優(yōu)化和動態(tài)編程提供了很多可能性,這篇文章主要介紹了使用C#強大的表達式樹實現(xiàn)對象的深克隆,需要的朋友可以參考下

一、表達式樹的基本概念

表達式樹是一個以樹狀結(jié)構(gòu)表示的表達式,其中每個節(jié)點都代表表達式的一部分。例如,一個算術(shù)表達式 a + b 可以被表示為一個樹,其中根節(jié)點是加法運算符,它的兩個子節(jié)點分別是 a 和 b。在 LINQ(語言集成查詢)中,表達式樹使得能夠?qū)?C# 中的查詢轉(zhuǎn)換成其他形式的查詢,比如 SQL 查詢。這樣,同樣的查詢邏輯可以用于不同類型的數(shù)據(jù)源,如數(shù)據(jù)庫、XML 文件等。由于表達式樹可以在運行時創(chuàng)建和修改,同樣的它們非常適合需要根據(jù)運行時數(shù)據(jù)動態(tài)生成或改變代碼邏輯的場景。這對于需要重復(fù)執(zhí)行的邏輯(比如本文提到的深克隆)是非常有用的,因為它們可以被優(yōu)化和緩存,從而提高效率。

二、創(chuàng)建和使用表達式樹

在 C# 中,我們可以通過 System.Linq.Expressions 命名空間中的類來創(chuàng)建和操作表達式樹。以下是一個創(chuàng)建簡單表達式樹的示例:

// 創(chuàng)建一個表達式樹表示 a + b
        ParameterExpression a = Expression.Parameter(typeof(int), "a");
        ParameterExpression b = Expression.Parameter(typeof(int), "b");
        BinaryExpression body = Expression.Add(a, b);
        // 編譯表達式樹為可執(zhí)行代碼
        var add = Expression.Lambda<Func<int, int, int>>(body, a, b).Compile();
        // 使用表達式
        Console.WriteLine(add(1, 2));  // 輸出 3

當我們定義了一個類型后,我們可以通過一個匿名委托進行值拷貝來實現(xiàn)深克?。?/p>

//自定義類型
public class TestDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}
//匿名委托
Func<TestDto, TestDto> deepCopy = x => new TestDto()
{
    Id = x.Id,
    Name = x.Name
};
//使用它
var a =new TestDto(){//賦值};
var b = deepCopy(a);//實現(xiàn)深克隆

那么想要自動化的創(chuàng)建這一匿名委托就會用到表達式樹,通過自動化的方式來實現(xiàn)匿名委托的自動化創(chuàng)建,這樣就可以實現(xiàn)復(fù)雜的自動化表達式創(chuàng)建從而不必依賴反射、序列化/反序列化等等比較消耗性能的方式來實現(xiàn)。核心的業(yè)務(wù)邏輯部分如下:首先我們需要知道表達式樹通過反射來遍歷對象的屬性,來實現(xiàn)x = old.x這樣的賦值操作。而對于不同的屬性比如數(shù)組、字典、值類型、自定義類、字符串,其賦值方案是不同的,簡單的值類型和字符串我們可以直接通過=賦值,因為這兩者的賦值都是“深”克隆。也就是賦值后的變量修改不會影響原始變量。而復(fù)雜的字典、數(shù)組、對象如果使用=賦值,則只會得到對象的引用,所以針對不同的情況需要不同的處理。

首先我們需要定義一個接口ICloneHandler,針對不同情況使用繼承該接口的處理類來處理:

interface ICloneHandler
{
    bool CanHandle(Type type);//是否可以處理當前類型
    Expression CreateCloneExpression(Expression original);//生成針對當前類型的表達式樹
}

接著我們定義一個擴展類和擴展函數(shù),用于處理深拷貝:

public static class DeepCloneExtension
{
    //創(chuàng)建一個線程安全的緩存字典,復(fù)用表達式樹
    private static readonly ConcurrentDictionary<Type, Delegate> cloneDelegateCache = new ConcurrentDictionary<Type, Delegate>();
    //定義所有可處理的類型,通過策略模式實現(xiàn)了可擴展
    private static readonly List<ICloneHandler> handlers = new List<ICloneHandler>
    {
       //在此處添加自定義的類型處理器
    };
    /// <summary>
    /// 深克隆函數(shù)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="original"></param>
    /// <returns></returns>
    public static T DeepClone<T>(this T original)
    {
        if (original == null)
            return default;
        // 獲取或創(chuàng)建克隆表達式
        var cloneFunc = (Func<T, T>)cloneDelegateCache.GetOrAdd(typeof(T), t => CreateCloneExpression<T>().Compile());
        //調(diào)用表達式,返回結(jié)果
        return cloneFunc(original);
    }
    /// <summary>
    /// 構(gòu)建表達式樹的主體邏輯
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    private static Expression<Func<T, T>> CreateCloneExpression<T>()
    {
        //反射獲取類型
        var type = typeof(T);
        // 創(chuàng)建一個類型為T的參數(shù)表達式 'x'
        var parameterExpression = Expression.Parameter(type, "x");
        // 創(chuàng)建一個成員綁定列表,用于稍后存放屬性綁定
        var bindings = new List<MemberBinding>();
        // 遍歷類型T的所有屬性,選擇可讀寫的屬性
        foreach (var property in type.GetProperties().Where(prop => prop.CanRead && prop.CanWrite))
        {
            // 獲取原始屬性值的表達式
            var originalValue = Expression.Property(parameterExpression, property);
            // 初始化一個表達式用于存放可能處理過的屬性值
            Expression valueExpression = null;
            // 標記是否已經(jīng)處理過此屬性
            bool handled = false;
            // 遍歷所有處理器,查找可以處理當前屬性類型的處理器
            foreach (var handler in handlers)
            {
                // 如果找到合適的處理器,使用它來創(chuàng)建克隆表達式
                if (handler.CanHandle(property.PropertyType))
                {
                    valueExpression = handler.CreateCloneExpression(originalValue);
                    handled = true;
                    break;
                }
            }
            // 如果沒有找到處理器,則使用原始屬性值
            if (!handled)
            {
                valueExpression = originalValue;
            }
            // 創(chuàng)建屬性的綁定
            var binding = Expression.Bind(property, valueExpression);
            // 將綁定添加到綁定列表中
            bindings.Add(binding);
        }
        // 使用所有的屬性綁定來初始化一個新的T類型的對象
        var memberInitExpression = Expression.MemberInit(Expression.New(type), bindings);
        // 創(chuàng)建并返回一個表達式樹,它表示從輸入?yún)?shù) 'x' 到新對象的轉(zhuǎn)換
        return Expression.Lambda<Func<T, T>>(memberInitExpression, parameterExpression);
    }
}

接下來我們就可以添加一些常見的類型處理器:

數(shù)組處理:

class ArrayCloneHandler : ICloneHandler
{
    Type elementType;
    public bool CanHandle(Type type)
    {
        //數(shù)組類型要特殊處理獲取其內(nèi)部類型
        this.elementType = type.GetElementType();
        return type.IsArray;
    }
    public Expression CreateCloneExpression(Expression original)
    {
        //值類型或字符串,通過值類型數(shù)組賦值
        if (elementType.IsValueType || elementType == typeof(string))
        {
            return Expression.Call(GetType().GetMethod(nameof(DuplicateArray), BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(elementType), original);
        }
        //否則使用引用類型賦值
        else
        {
            var arrayCloneMethod = GetType().GetMethod(nameof(CloneArray), BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(elementType);
            return Expression.Call(arrayCloneMethod, original);
        }
    }
    //引用類型數(shù)組賦值
    static T[] CloneArray<T>(T[] originalArray) where T : class, new()
    {
        if (originalArray == null)
            return null;
        var length = originalArray.Length;
        var clonedArray = new T[length];
        for (int i = 0; i < length; i++)
        {
            clonedArray[i] = DeepClone(originalArray[i]);//調(diào)用該類型的深克隆表達式
        }
        return clonedArray;
    }
    //值類型數(shù)組賦值
    static T[] DuplicateArray<T>(T[] originalArray)
    {
        if (originalArray == null)
            return null;
        T[] clonedArray = new T[originalArray.Length];
        Array.Copy(originalArray, clonedArray, originalArray.Length);
        return clonedArray;
    }
}

自定義類型處理(其實就是調(diào)用該類型的深克隆):

class ClassCloneHandler : ICloneHandler
{
    Type elementType;
    public bool CanHandle(Type type)
    {
        this.elementType = type;
        return type.IsClass && type != typeof(string);
    }
    public Expression CreateCloneExpression(Expression original)
    {
        var deepCloneMethod = typeof(DeepCloneExtension).GetMethod(nameof(DeepClone), BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(elementType);
        return Expression.Call(deepCloneMethod, original);
    }
}

接著我們就可以在之前的DeepCloneExtension中添加這些handles

private static readonly List<ICloneHandler> handlers = new List<ICloneHandler>
{
    new ArrayCloneHandler(),//數(shù)組
    new DictionaryCloneHandler(),//字典
    new ClassCloneHandler()//類
    ...
};

最后我們可以通過簡單的進行調(diào)用就可以實現(xiàn)深克隆了

var a = new TestDto() { Id = 1, Name = "小明", Child = new TestDto() { Id = 2, Name = "小紅" }, Record = new Dictionary<string, int>() { { "1年級", 1 }, { "2年級", 2 } }, Scores = [100, 95] };
var b = a.DeepClone();

總之,C# 的表達式樹提供了一個強大的機制,可以將代碼以數(shù)據(jù)結(jié)構(gòu)的形式表示出來,使得代碼可以在運行時進行檢查、修改或執(zhí)行。這為動態(tài)查詢生成、代碼優(yōu)化和動態(tài)編程提供了很多可能性。

到此這篇關(guān)于使用C#強大的表達式樹實現(xiàn)對象的深克隆的文章就介紹到這了,更多相關(guān)C#對象的深克隆內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

江门市| 洛隆县| 靖安县| 昭觉县| 永安市| 安乡县| 工布江达县| 平乡县| 海口市| 独山县| 新竹市| 九龙县| 叶城县| 江城| 金湖县| 潍坊市| 濉溪县| 全南县| 西城区| 大姚县| 呈贡县| 汕头市| 刚察县| 海南省| 沿河| 蓬安县| 磐石市| 葵青区| 东兰县| 宜川县| 铁力市| 贵定县| 桓台县| 美姑县| 噶尔县| 夏河县| 阿鲁科尔沁旗| 克什克腾旗| 昭苏县| 綦江县| 禄丰县|