C# 實現根據字段規則的賦值器(基於 Lambda 表達式樹實現)


前言

眾所周知,C#中最快的莫過於 lambda 和 emit。在很多場景下,多個實體類型具有相同規則的字段,例如:user_createtime,role_createtime,這兩個字段都表示創建時間,還有 user_audtflag,role_audtflag,都表示審核標識。它們都是由一個前綴加上固定的名稱所構成,具有一定規則。如果這樣的字段很多,而又不想每次手動對它們都賦值,首先想到的是利用反射實現。然而反射的性能是比較慢的。所以今天給大家用 lambda 表達式樹實現一個簡單的賦值器

源碼位置

ObjAssignMap:https://gitee.com/qiqigouwo/ObjAssignMap.git

安裝方法

PM> Install-Package ObjAssignMap 或者 dotnet add package ObjAssignMap

簡單使用

准備實體類

public class User
{
    public string ur_Name {get;set;}
    public DateTime? ur_audttime {get;set;}
    public string ur_audtman {get;set;}
    public string ur_audtflag {get;set;}
}

創建配置

public class AssignOption
{
    public const string Audt = "audt";//審核分組名
    public const string UnAudt = "unaudt";//棄審分組名

    //配置
    public static IObjAssign CreateAssign()
    {
        var config = new AssignConfig();
        //審核日期
        config.ForField<DateTime?>(Audt,UnAudt)//規則應用於 Audt 和 UnAudt 分組
            .SetRule(field => field.EndsWith("_audttime"))
            .SetVal(p => DateTime.Now);
        //審核人
        config.ForField<string>(Audt,UnAudt)
            .SetRule(field => field.EndsWith("_audtman"))
            .SetVal(p => GetUserID());
        //審核標志
        config.ForField<string>(Audt)//字段只應用於 Audt 分組
            .SetRule(field => field.EndsWith("_audtflag"))
            .SetVal(p => "1");
        //審核標志
        config.ForField<string>(UnAudt)
            .SetRule(field => field.EndsWith("_audtflag"))
            .SetVal(p => "0");
        return config.Build();
    }
}

使用

var user = new User();
var assign = AssignOption.CreateAssign();//實際使用中,需要設置為單實例
assign.Assign(user, AssignOption.Audt);
//assign.AssignObject(user, AssignOption.Audt);
/* 最后輸出結果
* user.ur_audttime  => 會調動 DateTime.Now 或獲取時間
* user.ur_audtman  => 會調用 GetUserID獲取用戶ID
* user.ur_audtflag => "1"
*/

核心源碼

首次對類型進行賦值時,會根據配置的字段規則進行匹配,並且構建表達式,編譯為委托,緩存到_map中,后面使用時就從緩存中取,不會再次構建。注意:委托的性能僅次於 C#源碼

private void AddAssignDet<T>(string groupName)
    where T : class
{
    _ = groupName ?? throw new ArgumentNullException(nameof(groupName));
    var type = typeof(T);
    var key = GetMapKey(type, groupName);
    lock (this)
    {
        if (_map.ContainsKey(key)) return;
        var fields = type.GetProperties();
        var p = Expression.Parameter(type, "p");
        var binds = new List<BinaryExpression>();
        var gp = this._rules.Where(x => x.GroupNames.Contains(groupName)).ToList();
        foreach (var rule in gp)
        {
            foreach (var field in fields)
            {
                if (rule?.Rule?.Invoke(field.Name) ?? false && rule.ValueType == field.PropertyType)
                {
                    MemberExpression member = Expression.Property(p, field);//left 字段
                    MethodCallExpression method = Expression.Call(rule?.ValueExpress, rule?.ValueMethod, member);//right 委托
                    BinaryExpression binary = Expression.Assign(member, method);//組合賦值
                    binds.Add(binary);
                }
            }
        }
        if (binds.Any())
        {
            _map.TryAdd(key, Expression.Lambda<Action<T>>(Expression.Block(binds), p).Compile());
        }
        else
        {
            _map.TryAdd(key, null);
        }
    }
}

源碼位置:https://gitee.com/qiqigouwo/ObjAssignMap.git


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM