首页 > 编程语言 >C# Lambda Mapper

C# Lambda Mapper

时间:2024-03-28 16:48:04浏览次数:31  
标签:Mapper Name C# item typeof PropertyType Expression string Lambda

场景

在业务开发中,从仓储至应用,中间一般还有一层模型映射服务,其中的核心主键俺管他叫映射器(Mapper)。现在业界已经有很多Mapper的实现方案了,多为自实现如反射同名映射,或者使用大名鼎鼎的AutoMapper

AutoMapper底层是有一些优化的,比很多自实现的反射同名映射要快,反射会占用大量时间。但是不管AutoMapper再快,肯定是没有直接赋值快( 直接new Data(){ Name = dataDto.Name }

一般来说,除非动态动编译层,否则除了Lambda之外,很难有比原生赋值还快的方法了。

Lambda Mapper

我的LambdaMapper的实现是基于我领域模型与视图模型的基本定义来编写的,读者可能需要按照各自的业务进行修改。

如我的领域模型:

    public class ApplicationMenuItem : EntityBase<Guid>
    {
        /// <summary>
        /// 访问时的默认参数min
        /// </summary>
        public string Parameter { get; set; }
        /// <summary>
        /// 导航地址
        /// </summary>
        [StringLength(150)]
        public string Path { get; set; }
        /// <summary>
        /// 图标
        /// </summary>
        public string Icon { get; set; }
        /// <summary>
        /// 上级菜单
        /// </summary>
        public ApplicationMenuItem Parent { get; set; }
        /// <summary>
        /// 是否不显示在导航栏
        /// </summary>
        public bool IsHidden { get; set; }
        /// <summary>
        /// 归属的客户端
        /// </summary>
        public CddApplication CddApplication { get; set; }
    }

Dto:

    public class ApplicationMenuItemDto : DtoBase<Guid>
    {
        /// <summary>
        /// 访问时的默认参数
        /// </summary>
        public string Parameter { get; set; }
        /// <summary>
        /// 导航地址
        /// </summary>
        public string Path { get; set; }
        /// <summary>
        /// 图标
        /// </summary>
        public string Icon { get; set; }
        /// <summary>
        /// 上级菜单
        /// </summary>
        public string ParentId { get; set; }
        public string ParentName { get; set; }
        /// <summary>
        /// 归属的客户端
        /// </summary>
        public string CddApplicationId { get; set; }
        public string CddApplicationName { get; set; }

两种模型相互的映射的规则

  1. 领域模型 => 视图模型
    1.1 同名同类型属性映射,同时提供不同类型但是同名类型的属性类型转换后赋值
    1.2 导航属性映射,如上面ApplicationMenuItemParent.IdParent.Name会映射到ApplicationMenuItemDtoParentIdParentName(当然这里面还有一些空值判断,如果Parent为空则不映射)
    1.3 层级映射,类似于使用AutoMapper的时候,会将Parent.Parent.Name映射至ParentParentName

  2. 视图模型 => 领域模型
    1.1 同名同类型属性映射,同时提供不同类型但是同名类型的属性类型转换后赋值
    1.2 从视图模型的属性中,拼接回导航属性,如上面ApplicationMenuItemDtoParentIdParentName会变成语句Parent = new ApplicationMenuItem(){ Id = applicationMenuItemDto.ParentId, Name = applicationMenuItemDto.ParentName}

代码实现

public class Mapper<TEntity, TEntityVM>
    where TEntity : class, new()
    where TEntityVM : class, new()
{
    /// <summary>
    /// 对于命名空间的约束
    /// </summary>
    private const string configNamespace = "您的命名空间";

    /// <summary>
    /// 转视图模型的lambda表达式缓存
    /// </summary>
    private static Func<TEntity, TEntityVM> _mapToEntityVMCache;
    /// <summary>
    /// 转实体模型的Lambda表达式缓存
    /// </summary>
    private static Func<TEntityVM, TEntity> _mapToEntityCache;

    static Mapper()
    {
        _mapToEntityVMCache = GetMapToEntityVMFunc();
        _mapToEntityCache = GetMapToEntityFunc();
    }

    /// <summary>
    /// 判断类型是否为可操作的列表类型
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    private static bool _isList(Type type)
    {
        if (typeof(System.Collections.IList).IsAssignableFrom(type))
        {
            return true;
        }
        foreach (var it in type.GetInterfaces())
        {
            if (it.IsGenericType && typeof(IList<>) == it.GetGenericTypeDefinition())
                return true;
        }
        return false;
    }

    /// <summary>
    /// 生成映射成视图模型的Lambda表达式
    /// </summary>
    /// <returns></returns>
    private static Func<TEntity, TEntityVM> GetMapToEntityVMFunc()
    {
        ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntity), "x");
        // 一组用于映射的模型绑定表达式
        List<MemberBinding> memberBindingList = new List<MemberBinding>();
        foreach (var entityProperty in typeof(TEntity).GetProperties())
        {
            // 这里的item是视图模型对应的属性
            var item = typeof(TEntityVM).GetProperty(entityProperty.Name);
            if (item == null)
            {
                // 如果是自定义类型
                if (entityProperty.PropertyType.FullName.Contains(configNamespace) && entityProperty.PropertyType.IsClass
                    && _isList(entityProperty.PropertyType) == false)
                {
                    var rootName = "";
                    var nextLevelMemberExpression = Expression.Property(parameterExpression, entityProperty);
                    var res = GetSubPropertyMapConfig<TEntityVM>(memberBindingList, rootName, nextLevelMemberExpression, entityProperty,
                        new List<MemberExpression>() { nextLevelMemberExpression });
                    memberBindingList = res.Item1;
                }
                // 否则就是真的没有
                else
                {
                    continue;
                }
            }
            else if (item.PropertyType == entityProperty.PropertyType)
            {
                // 如果是不能写的属性
                if (!item.CanWrite)
                    continue;
                MemberExpression eProperty = Expression.Property(parameterExpression, entityProperty.Name);
                MemberBinding memberBindingResult = Expression.Bind(item, eProperty);
                memberBindingList.Add(memberBindingResult);

                if (entityProperty.PropertyType.IsEnum)
                {
                    var enumNameProp = typeof(TEntityVM).GetProperty(entityProperty.Name + "Name");
                    // 搜索一下是否有后缀加Name的字符串值
                    if (enumNameProp != null)
                    {
                        MethodInfo methodInfo = entityProperty.PropertyType.GetMethod("ToString", new Type[] { });
                        var resultExpression = Expression.Call(eProperty, methodInfo);
                        MemberBinding enumNameMemberBindingResult = Expression.Bind(enumNameProp, resultExpression);
                        memberBindingList.Add(enumNameMemberBindingResult);
                    }
                }

            }
            // 其他类型转string
            else if (item.PropertyType != entityProperty.PropertyType && item.PropertyType == typeof(string))
            {
                // 如果是不能写的属性
                if (!item.CanWrite)
                    continue;
                MemberExpression memberExp = Expression.Property(parameterExpression, entityProperty.Name);
                // 获取ToString方法,一般来说,都应该是String类型
                MethodInfo methodInfo = memberExp.Type.GetMethod("ToString", new Type[] { });
                var resultExpression = Expression.Call(memberExp, methodInfo);
                // ToString()之后再传输过去
                MemberBinding memberBindingResult = Expression.Bind(item, resultExpression);
                memberBindingList.Add(memberBindingResult);
            }
            // string转其他类型
            else if (item.PropertyType != entityProperty.PropertyType && entityProperty.PropertyType == typeof(string))
            {
                // 如果是不能写的属性
                if (!item.CanWrite)
                    continue;
                MemberExpression property = Expression.Property(parameterExpression, typeof(TEntity).GetProperty(entityProperty.Name));
                MethodInfo parseMethod = item.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
                MethodCallExpression resultExpression = Expression.Call(parseMethod, new List<Expression>() { property });
                // p=> p.item.Name = p.item.Name
                MemberBinding memberBindingResult = Expression.Bind(item, resultExpression);
                memberBindingList.Add(memberBindingResult);
            }
        }
        // p => new TOut(){item.Name = p.item.Name}
        MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TEntityVM)), memberBindingList.ToArray());
        Expression<Func<TEntity, TEntityVM>> lambda = Expression.Lambda<Func<TEntity, TEntityVM>>(memberInitExpression, new ParameterExpression[] { parameterExpression });

        return lambda.Compile();
    }


    /// <summary>
    /// 二级类型映射处理
    /// </summary>
    /// <typeparam name="Target"></typeparam>
    /// <param name="memberBindings"></param>
    /// <param name="sourceType"></param>
    /// <returns></returns>
    private static Tuple<List<MemberBinding>, string, MemberExpression, List<MemberExpression>> GetSubPropertyMapConfig<Target>(List<MemberBinding> memberBindings, string rootName,
        MemberExpression nowLevelMemberExpression,
        PropertyInfo sourceSubTypeInfo,
        List<MemberExpression> historyNullValueValidateMembers)
    {
        var targetModelProps = typeof(Target).GetProperties();
        var sourceSubTypeProps = sourceSubTypeInfo.PropertyType.GetProperties();

        // 根名称,根据层级不断叠加
        rootName += sourceSubTypeInfo.Name;

        if (historyNullValueValidateMembers == null)
        {
            historyNullValueValidateMembers = new List<MemberExpression>();
        }

        var subClassProps = sourceSubTypeProps.Where(x => x.PropertyType.FullName.Contains(configNamespace) && x.PropertyType.IsClass).ToList();
        var baseClassProps = sourceSubTypeProps.Where(x => !x.PropertyType.FullName.Contains(configNamespace)).ToList();

        // 二级的二级属性映射
        foreach (var baseClassProp in baseClassProps)
        {
            var item = targetModelProps.FirstOrDefault(x => x.Name == rootName + baseClassProp.Name);
            if (item == null)
            {
                continue;
            }

            Expression nullValueValidateMemberExpression = null;
            if (historyNullValueValidateMembers == null)
            {
                return new Tuple<List<MemberBinding>, string, MemberExpression, List<MemberExpression>>(memberBindings, rootName, nowLevelMemberExpression, new List<MemberExpression>());
            }
            // 空值判断表达式拼接
            else
            {
                for (var i = 0; i < historyNullValueValidateMembers.Count; i++)
                {
                    if (i == 0)
                    {
                        nullValueValidateMemberExpression = Expression.Equal(historyNullValueValidateMembers[i], Expression.Constant(null));
                    }
                    else
                    {
                        nullValueValidateMemberExpression = Expression.OrElse(nullValueValidateMemberExpression, Expression.Equal(historyNullValueValidateMembers[i], Expression.Constant(null)));
                    }
                }
            }

            // 类型一致才进行映射
            if (item.PropertyType == baseClassProp.PropertyType)
            {
                MemberExpression memberExp = Expression.Property(nowLevelMemberExpression, baseClassProp);

                Expression conditionExpr = Expression.Condition(
                      nullValueValidateMemberExpression,
                      Expression.Default(memberExp.Type),
                      memberExp
                    );
                MemberBinding memberBindingResult = Expression.Bind(item, conditionExpr);
                memberBindings.Add(memberBindingResult);
            }
            else if (item.PropertyType == typeof(string))
            {
                MemberExpression memberExp = Expression.Property(nowLevelMemberExpression, baseClassProp);
                // 获取ToString方法,一般来说,都应该是String类型
                MethodInfo methodInfo = memberExp.Type.GetMethod("ToString", new Type[] { });
                var resultExpression = Expression.Call(memberExp, methodInfo);

                Expression conditionExpr = Expression.Condition(
                  nullValueValidateMemberExpression,
                  Expression.Default(typeof(string)),
                  resultExpression
                );
                MemberBinding memberBindingResult = Expression.Bind(item, conditionExpr);
                memberBindings.Add(memberBindingResult);
            }
            else if (baseClassProp.PropertyType == typeof(string))
            {
                MemberExpression memberExp = Expression.Property(nowLevelMemberExpression, baseClassProp);
                // 获取ToString方法,一般来说,都应该是String类型
                MethodInfo methodInfo = item.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
                var resultExpression = Expression.Call(methodInfo, new List<Expression>() { memberExp });

                Expression conditionExpr = Expression.Condition(
                  nullValueValidateMemberExpression,
                  Expression.Default(typeof(string)),
                  resultExpression
                );
                MemberBinding memberBindingResult = Expression.Bind(item, conditionExpr);
                memberBindings.Add(memberBindingResult);
            }
        }

        foreach (var subClassProp in subClassProps)
        {
            var nextLevelMemberExpression = Expression.Property(nowLevelMemberExpression, subClassProp);
            if (!historyNullValueValidateMembers.Any(x => x.Type == nextLevelMemberExpression.Type))
            {
                historyNullValueValidateMembers.Add(nextLevelMemberExpression);
            }
            // 如果二级仍是当前类型,不继续做处理,只映射一层
            if(subClassProp.PropertyType == sourceSubTypeInfo.PropertyType)
            {
                continue;
            }
            var res = GetSubPropertyMapConfig<Target>(memberBindings, rootName, nextLevelMemberExpression, subClassProp, historyNullValueValidateMembers);
        }

        return new Tuple<List<MemberBinding>, string, MemberExpression, List<MemberExpression>>(memberBindings, rootName, nowLevelMemberExpression, historyNullValueValidateMembers);
    }

    /// <summary>
    /// 生成映射成实体模型的Lambda表达式
    /// </summary>
    /// <returns></returns>
    private static Func<TEntityVM, TEntity> GetMapToEntityFunc()
    {
        ParameterExpression parameterExpression = Expression.Parameter(typeof(TEntityVM), "p");
        List<MemberBinding> memberBindingList = new List<MemberBinding>();
        // 遍历实体模型
        foreach (var item in typeof(TEntity).GetProperties())
        {
            // 同名的情况下
            // 如果是不能写的属性
            if (!item.CanWrite)
                continue;
            // 如果输出类型没有该属性
            if (typeof(TEntityVM).GetProperty(item.Name) == null)
            {
                // 如果是自定义类型
                if (item.PropertyType.FullName.Contains(configNamespace) && !item.PropertyType.IsEnum && _isList(item.PropertyType) == false)
                {

                    List<MemberBinding> tempMemberBindingList = new List<MemberBinding>();

                    // 获取实体模型二级

                    // p=>p.item.Name,拿到实体模型嵌套属性Id和Name
                    var theIdProp = typeof(TEntityVM).GetProperty(item.Name + "Id");
                    if (theIdProp != null)
                    {
                        MemberExpression idProperty = Expression.Property(parameterExpression, theIdProp);
                        if (idProperty == null) continue;
                        // TEntity.Id
                        var id = item.PropertyType.GetProperty("Id");
                        if (id == null) continue;
                        // 视图模型string转其他类型
                        if (id.PropertyType != theIdProp.PropertyType && theIdProp.PropertyType == typeof(string))
                        {
                            MethodInfo toGuid = id.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
                            MethodCallExpression expression = Expression.Call(toGuid, new List<Expression>() { idProperty });
                            Expression idConditionExpr = Expression.Condition(
                              Expression.Equal(Expression.Property(parameterExpression, item.Name + "Id"), Expression.Constant(null)),
                              Expression.Default(id.PropertyType),
                              expression
                            );
                            MemberBinding idMemberBinding = Expression.Bind(id, idConditionExpr);
                            tempMemberBindingList.Add(idMemberBinding);
                        }
                        else
                        {
                            MemberBinding idMemberBinding = Expression.Bind(item.PropertyType.GetProperty("Id"), idProperty);
                            tempMemberBindingList.Add(idMemberBinding);
                        }
                    }

                    var theNameProp = typeof(TEntityVM).GetProperty(item.Name + "Name");
                    if (theNameProp != null)
                    {
                        MemberExpression NameProperty = Expression.Property(parameterExpression, theNameProp);
                        MemberBinding NameMemberBinding = Expression.Bind(item.PropertyType.GetProperty("Name"), NameProperty);
                        tempMemberBindingList.Add(NameMemberBinding);
                    }


                    MemberInitExpression includeBoInitExpression = Expression.MemberInit(Expression.New(item.PropertyType), tempMemberBindingList.ToArray());
                    if (typeof(TEntityVM).GetProperty(item.Name + "Id").PropertyType == typeof(string))
                    {
                        Expression includeBoInitExpressionC = Expression.Condition(
                          Expression.Equal(Expression.Property(parameterExpression, item.Name + "Id"), Expression.Constant(null)),
                          Expression.Default(item.PropertyType),
                          includeBoInitExpression
                        );
                        MemberBinding memberString = Expression.Bind(item, includeBoInitExpressionC);
                        memberBindingList.Add(memberString);
                    }
                    else if (typeof(TEntityVM).GetProperty(item.Name + "Id").PropertyType == typeof(Guid)
                        || typeof(TEntityVM).GetProperty(item.Name + "Id").PropertyType == typeof(int))
                    {
                        Expression includeBoInitExpressionC = Expression.Condition(
                          Expression.Equal(Expression.Property(parameterExpression, item.Name + "Id"), Expression.Default(typeof(TEntityVM).GetProperty(item.Name + "Id").PropertyType)),
                          Expression.Default(item.PropertyType),
                          includeBoInitExpression
                        );
                        MemberBinding memberString = Expression.Bind(item, includeBoInitExpressionC);
                        memberBindingList.Add(memberString);
                    }
                    continue;
                }
                // 如果是字符串就绑定为""
                else if (item.PropertyType == typeof(string))
                {
                    // 将这个属性绑定到""
                    MemberBinding memberString = Expression.Bind(item, Expression.Constant(""));
                    memberBindingList.Add(memberString);
                }

                continue;
            }
            else if (item.PropertyType == typeof(TEntityVM).GetProperty(item.Name).PropertyType)
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TEntityVM).GetProperty(item.Name));
                // p=> p.item.Name = p.item.Name
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            // 基本类型 转string
            else if (item.PropertyType != typeof(TEntityVM).GetProperty(item.Name).PropertyType
                && typeof(TEntityVM).GetProperty(item.Name).PropertyType != typeof(string))
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TEntityVM).GetProperty(item.Name));
                MethodInfo toString = property.Type.GetMethod("ToString", new Type[] { });
                MethodCallExpression resultExpression = Expression.Call(property, toString);
                // p=> p.item.Name = p.item.Name
                MemberBinding memberBinding = Expression.Bind(item, resultExpression);
                memberBindingList.Add(memberBinding);

            }
            // string转 基本类型
            else if (item.PropertyType != typeof(TEntityVM).GetProperty(item.Name).PropertyType
                && typeof(TEntityVM).GetProperty(item.Name).PropertyType == typeof(string))
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TEntityVM).GetProperty(item.Name));
                MethodInfo toGuid = item.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
                MethodCallExpression resultExpression = Expression.Call(toGuid, new List<Expression>() { property });
                Expression guidValueExp = Expression.Condition(
                  Expression.Equal(property, Expression.Constant(null)),
                  Expression.Default(item.PropertyType),
                  resultExpression
                );
                // p=> p.item.Name = p.item.Name
                MemberBinding memberBinding = Expression.Bind(item, guidValueExp);
                memberBindingList.Add(memberBinding);
            }

        }
        // p => new TOut(){item.Name = p.item.Name}
        MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TEntity)), memberBindingList.ToArray());
        Expression<Func<TEntityVM, TEntity>> lambda = Expression.Lambda<Func<TEntityVM, TEntity>>(memberInitExpression, new ParameterExpression[] { parameterExpression });

        return lambda.Compile();
    }

    public static TEntityVM MapToApiEntity(TEntity tIn, Action<TEntity, TEntityVM> mapperExtensionAction = null)
    {
        if (tIn == null)
        {
            return null;
        }
        if (mapperExtensionAction == null)
        {
            return _mapToEntityVMCache(tIn);
        }
        else
        {
            var res = _mapToEntityVMCache(tIn);
            mapperExtensionAction(tIn, res);
            return res;
        }

    }

    public static TEntity MapToEntity(TEntityVM tout, Action<TEntityVM, TEntity> mapperExtensionAction = null)
    {
        if (tout == null)
        {
            return null;
        }
        if (mapperExtensionAction == null)
        {
            return _mapToEntityCache(tout);
        }
        else
        {
            var res = _mapToEntityCache(tout);
            mapperExtensionAction(tout, res);
            return res;
        }
    }

    public static List<TEntityVM> MapToApiEntity(IEnumerable<TEntity> tIns, Action<TEntity, TEntityVM> mapperExtensionAction = null)
    {
        if (tIns == null)
        {
            return null;
        }
        if (mapperExtensionAction == null)
        {
            return tIns.ToList().Select(x => _mapToEntityVMCache(x)).ToList();
        }
        else
        {
            return tIns.ToList().Select(x =>
            {
                var temp = _mapToEntityVMCache(x);
                mapperExtensionAction(x, temp);
                return temp;
            }).ToList();
        }
    }

    public static List<TEntity> MapToEntity(IEnumerable<TEntityVM> touts, Action<TEntityVM, TEntity> mapperExtensionAction = null)
    {
        if (touts == null)
        {
            return null;
        }
        if (mapperExtensionAction == null)
        {
            return touts.ToList().Select(x => _mapToEntityCache(x)).ToList();
        }
        else
        {
            return touts.ToList().Select(x =>
            {
                var temp = _mapToEntityCache(x);
                mapperExtensionAction(x, temp);
                return temp;
            }).ToList();
        }
    }
}

单句解释我就不做了,本质上就是表达式树的拼接,多看就理解了,实际上最核心的就是:

MemberBinding memberBinding = Expression.Bind(item, resultExpression);

以及一些情况下,需要先做不同类型的同名属性的映射后再进行Binding

MemberExpression property = Expression.Property(parameterExpression, typeof(TEntityVM).GetProperty(item.Name));
MethodInfo toString = property.Type.GetMethod("ToString", new Type[] { });
MethodCallExpression resultExpression = Expression.Call(property, toString);
// p=> p.item.Name = p.item.Name
MemberBinding memberBinding = Expression.Bind(item, resultExpression);
memberBindingList.Add(memberBinding);

或者导航属性拆解映射时,需要外层做一个判断导航属性是否为空的判断表达式

Expression includeBoInitExpressionC = Expression.Condition(Expression.Equal(Expression.Property(parameterExpression, item.Name + "Id"), 
    Expression.Default(typeof(TEntityVM).GetProperty(item.Name + "Id").PropertyType)),
    Expression.Default(item.PropertyType),
    includeBoInitExpression
);
MemberBinding memberString = Expression.Bind(item, includeBoInitExpressionC);
memberBindingList.Add(memberString);

最终生成Lambda Func,并且缓存在静态变量中,这样在一个服务的运行周期中,每两种实体的映射只需要编译一次Lambda表达式,往后的映射速度都会是最接近原生的,因为本质上已经编译成Func来执行了。

MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TEntity)), memberBindingList.ToArray());
Expression<Func<TEntityVM, TEntity>> lambda = Expression.Lambda<Func<TEntityVM, TEntity>>(memberInitExpression, new ParameterExpression[] { parameterExpression });
return lambda.Compile();

好久前测过一次速度,找不到数据了,现在懒得搞了,有读者自己测出来的话可以发一下出来,

标签:Mapper,Name,C#,item,typeof,PropertyType,Expression,string,Lambda
From: https://www.cnblogs.com/LazYu/p/18102030

相关文章

  • Task.Run(async () =>{}) 和 Task.Run(() =>{})区别
    Task.Run(async()=>{}):Task.Run(async()=>{}) 表示运行一个异步任务,传入的是一个异步lambda表达式。异步lambda表达式可以包含 await 操作符,允许在异步任务中等待其他异步操作完成。如果异步lambda表达式内部包含 await 操作,整个 Task.Run(async()=>{......
  • Docker镜像批量导出和导入脚本
    批量导出#!/bin/bash#设置导出镜像的目录EXPORT_DIR="/root/images"#确保导出目录存在mkdir-p"$EXPORT_DIR"#获取所有的镜像并导出IMAGES=$(dockerimages--format'{{.Repository}}:{{.Tag}}')#遍历所有的镜像forIMAGEin$IMAGES;......
  • 禁用edge、chrome浏览器自动更新
    禁用edge、chrome浏览器自动更新进入C:\ProgramFiles(x86)\Microsoft或C:\ProgramFiles(x86)\Google路径以edge为例:第一步:打开属性第二步:点击编辑第三步:修改权限......
  • pageoffice 6 实现pdf加盖印章和签字功能
    PageOffice支持两种电子印章方案,可实现对Word、Excel、PDF文档加盖PageOffice自带印章或ZoomSeal电子印章(全方位保护、防篡改、防伪造)。Word和Excel的盖章功能请参考:Word和Excel加盖印章和签字功能简易印章管理平台。PageOffice内置了简易印章管理平台功能,也称为自带电子印章,通过......
  • java中的static关键字
    Java中的static关键字修饰变量static修饰的变量属于类变量,被所有类所创建的对象共享修饰方法this关键字不能在static方法中使用static修饰的方法不能直接使用非static修饰的方法非static修饰的方法可以直接使用static修饰的方法修饰代码块静态的代码块是为了优化程......
  • Composer常见错误解决
    Composer是PHP中用于管理依赖关系的工具,常用于安装、更新和管理PHP项目中的第三方库和包。在使用Composer的过程中,可能会遇到一些常见的错误,下面列举几种常见的错误以及解决方法:1.缺少依赖关系或包无法找到错误描述:在运行composerinstall或composerupdate时,Composer报告......
  • LibreOffice 将word,excel,PowerPoint文件转换PDF
    安装LibreOffice并将Word和Excel文件转换为PDF文件,并设置文件存放路径的步骤如下:1.安装LibreOffice如果尚未安装LibreOffice,可以通过以下命令在Ubuntu上安装:sudoaptupdatesudoaptinstalllibreoffice2.使用LibreOffice将Word和Excel文件转换为PDF要将Word和Excel......
  • QCustomPlot多段y轴公用x轴、动态增加/移除曲线显示功能
    备注:1、动态增加/移除坐标系;2、多段y轴,共用同一个x轴;3、x轴y轴数据同步,当放大缩小表格时;4、通过定时器0.5s更新一次数据;****亲,感觉不错的话点个赞哦****一、项目中结合树形目录勾选框,进行动态增加和删除勾选框,通过定时器模拟数据进行显示connect(m_treeWidget,&Tr......
  • cuda原子操作
    如果不用原子操作,在进行计算直方图时会发生计算冲突d_b[i]为h_a中数字i有几个下面的代码将h_a全赋值为3,但d_b[3]却为1#include<iostream>#include"cuda_runtime.h"#include"device_launch_parameters.h"#defineN10__global__voidf(int*a,int*b){ intx=blo......
  • C++第五十七篇——RPC进程间通信
    第一步:新建一个空项目 第二步:新建一个IDL 第三步:生成一个GUID,编写RPCConn.idl RPCConn.idlimport"oaidl.idl";import"ocidl.idl";[uuid(1BA624D4-DC7D-484C-AF8C-0EF86C4A0555),version(1.0)]interfaceRPCConn{intAdd([in]inta,......