经典面试题之——如何自由转换两个没有继承关系的字段及类型相同的实体模型,AutoMapper?

永磁同步电机无传感器控制:HFI与ESMO技术详解 高频注入(HFI)和增强型滑模观测器(ESMO)是现代永磁同步电机(PMSM)无传感器控制的核心技术。HFI通过注入高频信号利用电机凸极效应获取转子位置,而ESMO则通过改进传统滑模观测器,有效抑制抖振并提升动态响应。这两种技术的结合特别适用于零低速区域的位置估计,在工业伺服、电动汽车等领域有广泛应用。方波高频注入作为实现方案之一,具有计算量小、实现简单的特点,配合自适应滤波等信号处理技术,可以在保证精度的同时降低系统成本。 阅读详情

这确实是一道基础题,不管是在java里面还是在C#里面,都属于一道非常基础的题,但很多童鞋竟然说没遇到过这样的场景,或者说学习基础的时候没重视过,所以自然不会了,那行,今天博主在这里就针对这个问题,做出详细的解释并由这个问题,同时,也给大家做个扩展学习吧。

在实际的项目当中,这是个非常非常需要的,我们经常需要在不同用途的实体之间相互转换进行数据传输,最典型的当然就是Entity和DTO之间的相互转换咯(不懂什么是DTO的自己去科普下,或者在这儿你看成是ViewModel也行,这无所谓)。当然,开这篇文章肯定不是只讲简简单单反射这么简单,那我写这篇文章可能有点大动干戈了,所以,你们赚了,除了讲反射,自然也就引出了各种创建对象的效率问题,以及除了反射还有哪些方式可以转换实体。

首先说一下,我听到的最多的答案,就是:

  1. new一个目标实体出来,然后把对应字段的值赋值上就好了

  2. 通过反射获取对象的属性,然后挨个循环属性,把对应属性名赋值到另一个对象里面

  3. 使用AutoMapper完成不同实体的转换。

上面这几个答案都是对的,只是答案1的童鞋钻漏子勉强回答对了,而答案2的通用性比较高了,答案3的就是拿来主义,有现成的直接用就好了,底层怎么实现的不知道…。可能有些童鞋以前答不上来的时候看到这些答案就恍然大悟了,而有的童鞋可能还是有点懵,这样的话确实应该回头再学一遍基础了。好吧,来点实际的吧。

那就从上面三个答案开始吧。

先准备两个实体吧:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class PersonDto
{
    public string Name { get; set; }
    public int Age { get; set; }
}
  1. 硬编码实现实体的相互转换
    最简单粗暴的方法也就是这样的咯,但如果面试这样回答,基本上不会加分。
Person p = new Person()
{
    Age = 10,
    Name = "张三"
};

PersonDto pd = new PersonDto()
{
    Name = p.Name,
    Age = p.Age
};

这样做,也不是不可以,毕竟效率是最高的,但是,通用性不强,如果要转换其他实体,每个都必须重新手写,不可复用,如果一个实体属性达到了几十上百个呢?这样写你不嫌手累嘛,看上去也不优雅是不。那下面这个,看上去稍微优雅点的:

  1. 委托实现实体的相互转换
    相比之上,稍微优雅了一点点,但,还是硬编码,面试这样回答的可能会加分;
Person p = new Person()
{
    Age = 10,
    Name = "张三"
};

Func<Person, PersonDto> func = c => new PersonDto()
{
    Age = c.Age,
    Name = c.Name
};

PersonDto pd = func(p);

这里直接写了个Func类型的委托,在委托里面硬编码给DTO实体的字段挨个赋值,看上去稍微优雅点了,毕竟用上了委托,哈哈……

那好,又优雅又不是硬编码的来了。

  1. 使用AutoMapper完成不同实体的转换
    当然,这拿来主义在实际项目中确实也用得非常多,包括博主我自己,在项目中也是用AutoMapper居多,毕竟人家实体转换效率还是蛮高的,面试中可能会加分。
Person p = new Person() { Age = 10, Name = "张三" };
Mapper.Initialize(m => m.CreateMap<Person, PersonDto>());
PersonDto pd = Mapper.Map<PersonDto>(p);

这代码,看上去确实很简单就完成了,拿来主义嘛,那要是就不准让你用AutoMapper,又要达到它这样的高性能,你咋办?!那好,后面有终极武器,比AutoMapper的转换效率更高效,所以看到这篇文章的童鞋们,你们赚大了!

  1. 通过反射实现实体的相互转换
    可能这样回答的人基础都是比较好的了,面试都会加分的。

首先准备一个方法,专门对实体进行映射:

/// <summary>
/// 实体映射
/// </summary>
/// <typeparam name="TDestination">目标实体</typeparam>
/// <param name="source">源实体</param>
/// <returns></returns>

public static TDestination MapTo<TDestination>(object source) where TDestination : new()
{
    TDestination dest = new TDestination();//创建目标实体对象
    foreach (var p in dest.GetType().GetProperties())//获取源实体所有的属性
    {
        p.SetValue(dest, source.GetType().GetProperty(p.Name)?.GetValue(source));//挨个为目标实体对应字段名进行赋值
    }
    return dest;
}

然后在需要进行实体转换的地方直接调这个方法就OK了;

Person p = new Person() { Age = 10, Name = "张三" };
PersonDto pd = MapTo<PersonDto>(p);

很好,这很优雅,但是,博主我觉得,还不够优雅,毕竟,可能好多人没看懂?

那好,来个更简单更直接的办法:反序列化进行实体转换;

  1. 通过Json反序列化实现实体的相互转换
    到这儿为止,很多童鞋就想不到了,实体转换还能通过json来进行;确实可以的,这也方便,而且还自带支持多成实体的映射转换,比如实体里面还包含List这样的数据结构;一句话就能搞定实体映射,不信你看:

首先通过nuget把Newtonsoft.Json引进来,然后coding…

Person p = new Person() { Age = 10, Name = "张三" };
PersonDto pd = JsonConvert.DeserializeObject<PersonDto>(JsonConvert.SerializeObject(p));

卧槽,居然这就搞定了,还能这么优雅?!那你试试吧。

上面这几种方式都是经常用到的,但是,当你进行超大批量的实体转换时,你会发现,反射和反序列化的方式出现瓶颈了,那有没有办法来优化呢,肯定有啊,不能优化的话那怎么去支撑千万级数据?!那你想到的是什么?表达式树?emit?

既然反射效率那么低,那是不是就不能用反射了?还是离不开反射,前方带你弯道超车,还请各位站稳扶好!

如果你在面试当中用到了下面这几种方式,那么,可能面试官都会膜拜你了,最后的可能,就是你选公司而不是公司选你了,哈哈…,当然,可能有点夸大其词,毕竟面试你的也不是什么技术菜鸟,至少会给你的面试大大加分!

  1. 表达式树实现实体的相互转换

来吧,拼接表达式,走起!

Person p = new Person() { Age = 10, Name = "张三" };
ParameterExpression parameterExpression = Expression.Parameter(typeof(Person), "p");
List<MemberBinding> memberBindingList = new List<MemberBinding>();//表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化(vs的注解。太生涩了,我这样的小白解释不了,大家将就着看)

foreach (var item in typeof(PersonDto).GetProperties()) //遍历目标类型的所有属性
{
    MemberExpression property = Expression.Property(parameterExpression, typeof(Person).GetProperty(item.Name));//获取到对应的属性
    MemberBinding memberBinding = Expression.Bind(item, property);//初始化这个属性
    memberBindingList.Add(memberBinding);
}

foreach (var item in typeof(PersonDto).GetFields())//遍历目标类型的所有字段
{
    MemberExpression property = Expression.Field(parameterExpression, typeof(Person).GetField(item.Name));//获取到对应的字段
    MemberBinding memberBinding = Expression.Bind(item, property);//同上
    memberBindingList.Add(memberBinding);
}

MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(PersonDto)), memberBindingList.ToArray());//初始化创建新对象

Expression<Func<Person, PersonDto>> lambda = Expression.Lambda<Func<Person, PersonDto>>(memberInitExpression, parameterExpression);
PersonDto pd = lambda.Compile()(p);

卧槽,看起来好复杂,不明觉厉啊!那,自己慢慢摸索下吧,都说了要站稳扶好的,这就不怪老司机了哈!

结果如上图所示,但是问题又来了,我们不可能只有一个类,也不可能只有一个Dto,那我们应该怎么实现呢? 对 ,可以用泛型来实现。

但是,博主我觉得还不够,每次转换还得写这么一大坨看不懂的东西,封装一下岂不更好用?那好,开始封装吧;

  1. 表达式树的封装实现通用实体的相互转换
public static TDestination ExpressionTreeMapper<TSource, TDestination>(TSource source)
{

    ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "p");
    List<MemberBinding> memberBindingList = new List<MemberBinding>();//表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化(vs的注解。太生涩了,我这样的小白解释不了,大家将就着看)

    foreach (var item in typeof(TDestination).GetProperties()) //遍历目标类型的所有属性
    {

        MemberExpression property = Expression.Property(parameterExpression, typeof(TSource).GetProperty(item.Name));//获取到对应的属性

        MemberBinding memberBinding = Expression.Bind(item, property);//初始化这个属性
        memberBindingList.Add(memberBinding);
    }

    foreach (var item in typeof(TDestination).GetFields())//遍历目标类型的所有字段
    {
        MemberExpression property = Expression.Field(parameterExpression, typeof(TSource).GetField(item.Name));//获取到对应的字段
        MemberBinding memberBinding = Expression.Bind(item, property);//同上
        memberBindingList.Add(memberBinding);
    }

    MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TDestination)), memberBindingList.ToArray());//初始化创建新对象

    Expression<Func<TSource, TDestination>> lambda = Expression.Lambda<Func<TSource, TDestination>>(memberInitExpression, parameterExpression);

    return lambda.Compile()(source); //拼装是一次性的

}

封装之后,调用倒是方便了,但我觉得没区别,封装之后每次调用这个方法不也得走一遍编译表达式树的过程,这个过程岂不多余了?这个过程性能瓶颈很大。

那好,能不能把编译之后的表达式树缓存起来?答案是肯定可以的,继续优化,走起;

  1. 表达式树缓存实现通用实体的相互转换
    实现思路:把每次编译后的表达式树缓存起来,如果存在,直接拿现成的编译好的表达式树调用就好了
/// <summary>
/// 生成表达式目录树。字典缓存
/// </summary>
public class ExpressionMapper
{

    private static Dictionary<string, object> _dic = new Dictionary<string, object>();//缓存字典,缓存后的就是硬编码所以性能高。

    /// <summary>
    /// 字典缓存表达式树
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TDestination"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    
    public static TDestination Map<TSource, TDestination>(TSource source)
    {
        string key = $"funckey_{typeof(TSource).FullName}_{typeof(TDestination).FullName}";
        if (!_dic.ContainsKey(key)) //如果该表达式不存在,则走一遍编译过程
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();//表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化(vs的注解。太生涩了,我这样的小白解释不了,大家将就着看)
            foreach (var item in typeof(TDestination).GetProperties()) //遍历目标类型的所有属性
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TSource).GetProperty(item.Name));//获取到对应的属性
                MemberBinding memberBinding = Expression.Bind(item, property);//初始化这个属性
                memberBindingList.Add(memberBinding);
            }

            foreach (var item in typeof(TDestination).GetFields())//遍历目标类型的所有字段
            {
                MemberExpression property = Expression.Field(parameterExpression, typeof(TSource).GetField(item.Name));//获取到对应的字段
                MemberBinding memberBinding = Expression.Bind(item, property);//同上
                memberBindingList.Add(memberBinding);
            }

            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TDestination)), memberBindingList.ToArray());//初始化创建新对象

            Expression<Func<TSource, TDestination>> lambda = Expression.Lambda<Func<TSource, TDestination>>(memberInitExpression, parameterExpression);
            _dic[key] = lambda.Compile(); //拼装是一次性的
        }
        return ((Func<TSource, TDestination>)_dic[key]).Invoke(source);
    }

}

恩,这样缓存起来,再执行重复类型的转换,就直接取缓存好的表达式树进行调用了,性能貌似提升了,非常棒!但博主我认为,这还有优化的余地,既然有了缓存,那我干脆直接把泛型搬到整个类上面,进行缓存起来,好的,走起;

  1. 表达式树泛型缓存实现通用实体的相互转换
/// <summary>
/// 生成表达式目录树  泛型缓存
/// </summary>
public class ExpressionGenericMapper
{
    private static object func;
    public static TDestination Map<TSource, TDestination>(TSource source)
    {
        if (func is null)//如果表达式不存在,则走一遍编译过程
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "p");

            var memberBindingList = new List<MemberBinding>();//表示绑定的类派生自的基类,这些绑定用于对新创建对象的成员进行初始化(vs的注解。太生涩了,我这样的小白解释不了,大家将就着看)

            foreach (var item in typeof(TDestination).GetProperties()) //遍历目标类型的所有属性
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TSource).GetProperty(item.Name));//获取到对应的属性
                MemberBinding memberBinding = Expression.Bind(item, property);//初始化这个属性
                memberBindingList.Add(memberBinding);
            }

            foreach (var item in typeof(TDestination).GetFields())

            {
                MemberExpression property = Expression.Field(parameterExpression, typeof(TSource).GetField(item.Name));//获取到对应的字段
                MemberBinding memberBinding = Expression.Bind(item, property);//同上
                memberBindingList.Add(memberBinding);
            }

            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TDestination)), memberBindingList.ToArray());//初始化创建新对象
            Expression<Func<TSource, TDestination>> lambda = Expression.Lambda<Func<TSource, TDestination>>(memberInitExpression, parameterExpression);
            func = lambda.Compile();
        }
        return ((Func<TSource, TDestination>)func)(source); //拼装是一次性的
    }
}
  1. 最后,来个性能测试吧
    我们挨个用这些方法,都循环映射1,000,000次,看谁跑得最快!

单线程测试代码:

static void Main(string[] args)
{

    Person p = new Person() { Age = 10, Name = "张三" };
    Stopwatch sw = new Stopwatch();
   
    sw.Start();
    for (int i = 0; i < 1_000_000; i++)
    {
        PersonDto pd = new PersonDto() { Name = p.Name, Age = p.Age };
    }
    sw.Stop();

    Console.WriteLine($"使用硬编码映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    Func<Person, PersonDto> func = c => new PersonDto()
    {
        Age = c.Age,
        Name = c.Name
    };

    sw.Restart();
    for (int i = 0; i < 1_000_000; i++)
    {
        PersonDto pd = func(p);
    }
    sw.Stop();
    
    Console.WriteLine($"使用委托映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");
   
    sw.Restart();
    Mapper.Initialize(m => m.CreateMap<Person, PersonDto>()); 
    for (int i = 0; i < 1_000_000; i++)
    {
        PersonDto pd = Mapper.Map<PersonDto>(p);
    }
    sw.Stop();
    
    Console.WriteLine($"使用AutoMapper映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");
   
    sw.Restart();
    for (int i = 0; i < 1_000_000; i++)
    {
        PersonDto pd = MapTo<PersonDto>(p);
    }
    sw.Stop();
    
    Console.WriteLine($"使用反射映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");
   
    sw.Restart();
    for (int i = 0; i < 1_000_000; i++)
    {
        PersonDto pd = JsonConvert.DeserializeObject<PersonDto>(JsonConvert.SerializeObject(p));
    }
    sw.Stop();
    
    Console.WriteLine($"使用Json反序列化映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");
   
    sw.Restart();
    for (int i = 0; i < 1_000_000; i++)
    {
        PersonDto pd = ExpressionTreeMapper<Person, PersonDto>(p);
    }
    sw.Stop();

    Console.WriteLine($"使用编译表达式树映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();
    for (int i = 0; i < 1_000_000; i++)
    {
        PersonDto pd = ExpressionMapper.Trans<Person,PersonDto>(p);
    }
    sw.Stop();

    Console.WriteLine($"使用缓存编译表达式树映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();
    for (int i = 0; i < 1_000_000; i++)
    {

        PersonDto pd = ExpressionGenericMapper.Map<Person,PersonDto>(p);

    }
    sw.Stop();

    Console.WriteLine($"使用泛型缓存编译表达式树映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();

    Console.ReadKey();
}

测试结果:

并行计算测试代码:

static void Main(string[] args)
{

    Person p = new Person() { Age = 10, Name = "张三" };

    Stopwatch sw = new Stopwatch();

    sw.Start();

    Parallel.For(0, 1_000_000, (l, state) =>
      {
          PersonDto pd = new PersonDto() { Name = p.Name, Age = p.Age };
      });

    sw.Stop();

    Console.WriteLine($"使用硬编码映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    Func<Person, PersonDto> func = c => new PersonDto()
    {
        Age = c.Age,
        Name = c.Name
    };

    sw.Restart();

    Parallel.For(0, 1_000_000, (l, state) =>
    {
        PersonDto pd = func(p);
    });

    sw.Stop();

    Console.WriteLine($"使用委托映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();

    Mapper.Initialize(m => m.CreateMap<Person, PersonDto>());

    Parallel.For(0, 1_000_000, (l, state) =>
    {
        PersonDto pd = Mapper.Map<PersonDto>(p);
    });

    sw.Stop();

    Console.WriteLine($"使用AutoMapper映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();
    Parallel.For(0, 1_000_000, (l, state) =>
    {
        PersonDto pd = MapTo<PersonDto>(p);
    });
    sw.Stop();

    Console.WriteLine($"使用反射映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();
    Parallel.For(0, 1_000_000, (l, state) =>
    {

        PersonDto pd = JsonConvert.DeserializeObject<PersonDto>(JsonConvert.SerializeObject(p));

    });
    sw.Stop();

    Console.WriteLine($"使用Json反序列化映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();
    Parallel.For(0, 1_000_000, (l, state) =>
    {
        PersonDto pd = ExpressionTreeMapper<Person, PersonDto>(p);
    });
    sw.Stop();

    Console.WriteLine($"使用编译表达式树映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();
    Parallel.For(0, 1_000_000, (l, state) =>
    {
        PersonDto pd = ExpressionMapper.Trans<Person, PersonDto>(p);
    });
    sw.Stop();

    Console.WriteLine($"使用缓存编译表达式树映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();
    Parallel.For(0, 1_000_000, (l, state) =>
    {
        PersonDto pd = ExpressionGenericMapper.Map<Person, PersonDto>(p);
    });
    sw.Stop();

    Console.WriteLine($"使用泛型缓存编译表达式树映射1000000次耗时{sw.Elapsed.TotalMilliseconds}ms");

    sw.Restart();

    Console.ReadKey();

}

测试结果:
很显然,不管是串行代码还是并行代码,硬编码效率肯定是最高的,至于为什么直接new的硬编码在并行的时候似乎慢了点,这就需要你们从多线程和内存的角度考虑下了,Newtonsoft.Json虽然是高性能的序列化插件,但是使用不当也会造成性能瓶颈的,你们如果用JavascriptSerializer序列化,估计看出来的差距更大了,所以一开始我也就选择Newtonsoft.Json来做本次的评测,也能看出来,表达式树不缓存的时候也是非常耗性能的,毕竟每次都要走一遍编译过程,所以就慢了,而一旦加上了缓存机制,就得到了质的飞跃,而最后的表达式树泛型缓存的写法,性能最接近硬编码的写法,所以,优化无止境!

至于为什么AutoMapper的性能还没有表达式树高,有兴趣的童鞋可以去github研究下它的源码,它的底层实现其实是用的emit写法,这篇文章就不准备再讲emit了,估计这个更容易把你们给搞晕,毕竟涉及到很多中间语言代码(MSIL),所以,有兴趣的你,可以作为扩展研究。

SCADA|用KingSCADA实现设备台账的查询功能 以上为用KingSCADA实现设备台账的查询功能,另外还有一些细节功能,比如当点击增加按钮时弹出的信息窗口内的信息希望是在选中的某行信息,只要找到差不多的设备,修改个别参数即可,避免增加时弹出空白页,所有信息都需要填写。以上为实现设备台账查询的最简单实现,实际项目中可能会更复杂,你做过哪些设备台账或相关的功能,有比较好的创意或高难度功能方法,欢迎在留言区评论,或在交流群探讨,互通有无,共同进步。首先完成界面的组态工作,主要是通过查询按钮,查询SQLServer数据库的设备台账数据,然后填充到报表内。 阅读详情

相关推荐

Landsat9 地表温度反演方法

landsat9地表温度反演及缺失值处理方法

xiangliu12345的博客 3915

泛型实现List<T>转List<U>

[TOC]@TOC 泛型实现List<T>转List<U> 支持T和U的属性名一致,调用converListT2ListU(List source, Class u) 支持T和U的属性名不一致,调用converListT2ListU(List source, Class u, String relationFields) 用代码说话 /** * 将List<T>转为List<U>,T和U赋值的属性名必须一致(底层采用Spring的BeanUti

hzp 5794

AI 编程组合之deepseek+vscode+cline插件,使用deepseek大模型实现代码自动生成

本文介绍了VSCODE下cline插件的安装结合DeepSeek-V3,ai编程的组合套件,举了两个例子一个是生成登录页面,一个是生成贪吃蛇游戏

技术博客 7万+

.net 反射实现两个相同结构实体类的转换

两个结构相同的实体类的转换,T2实体类的属性数可以大于T1的属性数,可用于api接口实体类参数到数据库实体的转换。 public static List CopyToList(List source)         {             List t2List = new List();             T2 model = default(T2);

dreamparks的专栏 4558

SocraticLM: Exploring Socratic Personalized Teaching with Large Language Models

大型语言模型(LLM)被认为是推进智能教育的一项关键技术,因为它们展示了深入理解教学场景和为学生提供个性化指导的潜力。然而,当前个性化教学中基于LLM的应用主要遵循“问答”范式,学生被动地获得答案和解释。在本文中,我们提出了苏格拉底式教学模式(SocraticLM ),它实现了一种苏格拉底式的“发人深省”的教学范式,实现了真正的课堂教师的角色,让学生积极参与到真正掌握解决问题所需的思考过程中。

weixin_43961909的博客 2880

RK3568下GPIO模拟串口

在嵌入式开发中,硬件 UART 资源可能被其他外设占用。此时,通过 GPIO 模拟 UART(软串口)成为一种灵活的解决方案。本文基于 RK3568 平台,结合 Linux 内核模块,实现高精度软串口通信,并深入分析关键技术细节。可以看到已经接收到数据了,可以自己创建自定义的设备文件到/dev下,也可以按照串口设备的标准创建一个设备,后面有时间我写一篇和标准串口设备结合的gpio模拟串口文章。RK3568 GPIO 模拟串口(软串口)实现详解。将编译好的驱动放到板子上运行。再写个Makefile。

文石_2009的博客 363

通过反射的方法,比较两个相同实体的属性和属性值是否一致

/// <summary> /// 判断两个实体类是否相等 /// </summary> /// <param name="processObj">对象1</param> /// <param name="processObj2">对象...

weixin_30279671的博客 370

C#里用HttpListener实现WEB API接口服务端

本文介绍了一个基于WinForm的HTTP服务实现方案。该方案使用HttpListener类创建了一个支持JSON POST请求处理的轻量级Web服务器,主要特点包括:1) 纯线程方式实现请求监听和处理;2) 提供标准化的JSON响应格式;3) 支持自定义请求处理逻辑;4) 包含完整的日志记录功能。代码示例展示了如何初始化服务、处理不同类型的请求(包括JSON POST),并提供了线程安全的UI更新机制。该实现适用于需要简单HTTP接口的Windows桌面应用程序,可作为程序间通信的基础设施。

大坡3D软件开发 226

《.NET 下最快比较两个文件内容是否相同》之我的看法验证

我对文件对比这一块还是比较感兴趣的,也想知道哪种方式性价比最高,效率最好,所以,根据这篇文章,我自己也自测一下,顺便留出自己对比的结果,供大佬们参考一二。大致对比方案我这边根据文章里的主要三个方案1.MD52.缓存长度读取比较3.缓存长度读取(Span)比较4.Hash2565.CRC(最后补的)新增了Hash256模式,原因是因为GitHub就是用Hash256来确定文件的唯一性的,所...

dotNET跨平台 301

Ollama 在不同操作系统上的详细使用,及用python进行调用实战

本文介绍了Ollama的安装配置及Python调用方法。主要内容包括:1)Windows/macOS/Linux/Docker等多种安装方式;2)Ollama基础命令,涵盖模型管理、运行和服务控制;3)Python调用教程,包含官方库使用、自定义客户端、多轮对话、参数设置等高级功能,以及直接API调用示例。文章提供了完整的代码片段,适合开发者快速上手使用Ollama进行本地大模型部署和开发。

数据知道的博客 1231

Google Earth Engine 红树林制图方法的代码(三个模块)

谷歌地球引擎红树林制图方法(GEM)提供了一种直观、易用且可复制的工具,适用于广泛的非专业沿海管理者和决策者。该工具全面回顾并整合了相关的红树林遥感文献,并利用云计算的力量,包括简化的基于图像的潮汐校准方法。GEM 可免费用于非营利用途,并在 GEE 中运行,包含全面且详细注释的代码。GEM 专门设计用于绘制全球范围内多日期红树林分布并量化其动态变化。目前可用的工具和方法未能充分利用沿海管理者通常持有的丰富地方专业知识——GEM 致力于填补这一空白,帮助结合地方专业知识与 GEE 的云计算能力。

此星光明博客 559

automapper 面试问题

一.AutoMapper使用中的问题 1. 指定值只会执行一次 public class MomanBaseProfile : Profile { public MomanBaseProfile() { CreateMap<RequestBase, MomanEntity>() .ForMember(d => d.ID, op => op.Ignore()) .ForMember(

极客神殿 401

使用lightGBM进行数据建模及预测

在机器学习领域中,数据建模和预测一直是非常重要的任务。而lightGBM作为一种基于梯度提升算法的高效机器学习框架,被广泛应用于数据建模和预测中。本文将介绍如何使用lightGBM进行数据建模和预测。到此,我们已经成功使用lightGBM对数据进行了建模和预测。使用lightGBM可以快速、高效地完成数据建模和预测任务,是机器学习领域中不可或缺的工具之一。使用lightGBM进行数据建模及预测。

qq_37934722的博客 1016

经典面试题之——如何自由转换两个没有继承关系的字段及类型相同的实体模型,AutoMapper?...

相信很多童鞋们都被问到过这个问题,不管是在面试的时候被问过,还是笔试题里考过,甚至有些童鞋们找我要学习资料的时候我也考过这个问题,包括博主我自己,也曾被问过,而且博主现在有时作为公司的面试官,也喜欢问应试者这样的问题。 这确实是一道基础题,不管是在java里面还是在C#里面,都属于一道非常基础的题,但很多童鞋竟然说没遇到过这样的场景,或者说学习基础的时候没重视过,所以自然不会了,那行,...

weixin_30840573的博客 342

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

MVVM+Prism+EF+Task+MQTT高频面试题

框架选型:选择Prism因团队熟悉其模块化架构,内置和导航服务符合MES复杂场景需求。框架扩展:有的,比如在MES的登录模块,我们需要安全地绑定密码。WPF的PasswordBox不能直接绑定,这是框架的一个限制。我们通过扩展附加属性实现了安全的双向绑定。--自定义扩展属性 附加属性-->

weixin_45499919的博客 1097

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C#中类名不一样,类成员完全一样的相互转化

【代码】C#中类名不一样,类成员完全一样的相互转化。

qq165285727的专栏 814

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

利用反射强制转换结构相同的类(类之间无需有继承关系)

using System;   using System.Reflection;   using System.Collections;   using System.Collections.Generic;     namespace Common.Helpers   {       ///         /// 类型转换器(利用反射)        ///

yw1688的专栏 596

【c#】类型转换

隐式转换 当两个不同类型的操作数进行运算时,编译器会试图对其进行自动类型转换,使两者变为同一类型。不同的数据类型具有不同的肤质空间,如果试图将一个需要较大赋值为空间的数据转换为赋值空间较小的数据,就会出现错误。 隐式转换一般在不同类型的数据进行混合运算时发生,由c#语言编译器自动完成。隐式转换遵循以下规则。 如果参与运算的数据类型不相同,则先转换成同一类型,然后进行运算。 转换时按数据长度...

化身孤岛的鲸 666

转换2种实体类,两张表字段差不多

二种是org.springframework.beans 类似迭代器转换。都使用JDK 1.8 后的 Lambda 表达式 ,强烈推荐!转换方式分几种 第一种是 JSON。开发中很多情况都会这样。

Chcvn 456

java 两个实体类转换_java 实体类相互转换赋值,代替get和set

package com.yzw.manager.util;import java.lang.reflect.Field;import java.lang.reflect.Modifier;/*** yangzhiwei* 2个实体类相互转换赋值()* 字段名的类型和名称必须完全相同才可以,继承的父类字段无法赋值* 代替set和get重复代码*/public class ReflectToBean ...

weixin_34315803的博客 2935

两个相同的类互相关联

代码 //类1 auto mpPaint1 = it.value().mpImageWnd->mpImageWnd->mpCenterWidget->m_pMainView->m_pPixmapObject->m_pPixmapItem; //类2 auto mpPaint2 = (it+1).value().mpImageWnd->mpImageWnd->mpCenterWidget->m_pMainView->m_pPixmapObject-

一条小闲鱼的博客 357

C# 实体类转换的两种方式

将一个实体类的数据赋值到另一个实体类中(亦或者实现深拷贝)。 以下提供两种方式,一种是序列化,一种是泛型+反射; 实现功能: 两个实体类数据转换赋值 开发环境: 开发工具: Visual Studio 2013 .NET Framework版本:4.5 实现代码: //学生类 private class Student { public string name { get; set; } public int age { get; set; } .

qq_27410185的博客 7570

java 两个实体类转换_实体类之间的转换

packagecom.dongl.utils;importorg.dozer.DozerBeanMapper;importorg.springframework.beans.BeansException;importorg.springframework.beans.FatalBeanException;importorg.springframework.util.Assert;importorg...

weixin_30240765的博客 1万+

两个实体(有相同字段)如何赋值

  a中字段 id  name   b中字段 id name sex  import org.springframework.beans.BeanUtils; BeanUtils.copyProperties(a, b);   将a中有与b相同的字段直接赋值给b  

qq_36014509的博客 5919

Java —— 将一个实体复制给另一个实体,两个实体中有相同字段

问题 目前有两个实体,部分字段相同,部分字段不同,想将一个实体复制给另一个实体,但不想写冗长的复制代码,应该如何处理呢? 解决 import org.apache.commons.beanutils.BeanUtils; //a复制给b BeanUtils.copyProperties(a, b); ...

看了就会暴富的博客! 4784

通过反射,给两个相同的实体类赋值

public static Object TheAssignment(Object model,Object model2) throws Exception { Class clazz=model.getClass(); Class clazz2=model2.getClass(); Field[] fields=clazz.getDeclaredFields(); Field[] fields2=clazz2.getDeclaredFields(); ...

qq_37490756的博客 407
上一篇: AutoMapper学习
下一篇: Linq之GroupBy用法
.NET跨平台
博客等级 码龄15年 6066粉丝 738原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值