C# 两个不相同实体转换,除了反射还有其它的方法吗?百万级数据转换!

一叶无秋 2018-12-19 10:51:18
加精
求数据百万级高效率两个不相同的实体转换,以前是通过实体特性获取需要转换的字段,效率一直不怎么样,想要个高效率的转换方法,现在一点思路也没有。

public static T ToClientEntity<T>(this ServerEntityBase sData) where T: ClientDataEntity,new()
{
T tempResult = new T();
PropertyInfo serProperty;
object proValue;
foreach (PropertyInfo item in tempResult.GetType().GetProperties())
{
EntityConvertAttribute convertAtt = Attribute.GetCustomAttribute(item, typeof(EntityConvertAttribute)) as EntityConvertAttribute;
if (convertAtt == null)
{
continue;
}
serProperty = sData.GetType().GetProperty(convertAtt.ServerEntity_Name);
if (serProperty == null)
{
continue;
}
proValue = serProperty.GetValue(sData);
if(proValue == null)
{
continue;
}
if (!convertAtt.IsTypeConvert || item.PropertyType.Name == proValue.GetType().Name)
{
item.SetValue(tempResult, Convert.ChangeType(proValue,item.PropertyType));
SpecialConvert(tempResult, proValue, item);
continue;
}
MethodInfo convertFun = tempResult.GetType().GetMethod(convertAtt.ConvertToClient, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
object setValue = convertFun?.Invoke(tempResult, new object[] { proValue });
if (setValue == null)
{
continue;
}
item.SetValue(tempResult, setValue);
SpecialConvert(tempResult, setValue, item);
}
return tempResult;
}

这是以前的实体转换,
...全文
15887 28 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
孤独的海啊 2019-01-27
  • 打赏
  • 举报
回复
建议你写个代码生成器? 直接new 然后赋值。然后多线程并行处理。
lc011289 2019-01-04
  • 打赏
  • 举报
回复
mark,我公司用的框架就是通过反射获取数据库中的数据,数据量一大就非常难受
啊宝儿姐 2019-01-03
  • 打赏
  • 举报
回复
高大上的问题。如果明确知道要转换和转换后的对象,直接new一个,赋值就好。 如果不知道的话,特别是不知道对象的属性类型,那就不知道了....
qq_32182723 2019-01-03
  • 打赏
  • 举报
回复
尽一切可能避免反射。如果能基于接口设计软件,为什么反射?
一叶无秋 2019-01-03
  • 打赏
  • 举报
回复
我是后期接手的项目,所以对于当时为什么服务端返回类型和客户端类型为什么不一样,这我也不清楚,都是在客户端定义特性,指定字段转换,项目进度问题所以就直接用到反射。
谢谢大家。

public delegate void SetValueDelegate(object target, object arg);
public static class DynamicMethodFactory
{
public static SetValueDelegate CreatePropertySetter(PropertyInfo property)
{
if (property == null)
throw new ArgumentNullException("property");

if (!property.CanWrite)
return null;

MethodInfo setMethod = property.GetSetMethod(true);

DynamicMethod dm = new DynamicMethod("PropertySetter", null,
new Type[] { typeof(object), typeof(object) }, property.DeclaringType, true);


ILGenerator il = dm.GetILGenerator();

if (!setMethod.IsStatic)
{
il.Emit(OpCodes.Ldarg_0);
}
il.Emit(OpCodes.Ldarg_1);

EmitCastToReference(il, property.PropertyType);
if (!setMethod.IsStatic && !property.DeclaringType.IsValueType)
{
il.EmitCall(OpCodes.Callvirt, setMethod, null);
}
else
il.EmitCall(OpCodes.Call, setMethod, null);

il.Emit(OpCodes.Ret);

return (SetValueDelegate)dm.CreateDelegate(typeof(SetValueDelegate));
}
private static void EmitCastToReference(ILGenerator il, Type type)
{
if (type.IsValueType)
il.Emit(OpCodes.Unbox_Any, type);
else
il.Emit(OpCodes.Castclass, type);
}
}

上面是我在网上查到的 关于反射优化,用到委托和Emit,效率上比直接赋值慢了十几倍,但是比反射快了一半。
lzblqq 2019-01-02
  • 打赏
  • 举报
回复
.net 反射效率有点低。
丰云 2018-12-29
  • 打赏
  • 举报
回复
就实际解决问题来说,装饰模式,算是比较快的解决方案了,理论上讲没有比这更快的转换方案了
shaokun668 2018-12-27
  • 打赏
  • 举报
回复
23种设计模式之一,包装模式。
丁劲犇 2018-12-25
  • 打赏
  • 举报
回复
动态语言特性,不知道如何破性能的难题。
还是基于接口比较好。
marmothac 2018-12-25
  • 打赏
  • 举报
回复
mark,不为别的,以后留着用
zhishiheng 2018-12-25
  • 打赏
  • 举报
回复
就要用反射,就用,就用
  • 打赏
  • 举报
回复
反射比较慢吧
liuhongwei90 2018-12-21
  • 打赏
  • 举报
回复
直接new对象赋值属性不干嘛?
真相重于对错 2018-12-21
  • 打赏
  • 举报
回复
用反射是最慢的方法
真相重于对错 2018-12-21
  • 打赏
  • 举报
回复
class Digit
{
    public Digit(double d) { val = d; }
    public double val;
    // ...other members

    // User-defined conversion from Digit to double
    public static implicit operator double(Digit d)
    {
        return d.val;
    }
    //  User-defined conversion from double to Digit
    public static implicit operator Digit(double d)
    {
        return new Digit(d);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Digit dig = new Digit(7);
        //This call invokes the implicit "double" operator
        double num = dig;
        //This call invokes the implicit "Digit" operator
        Digit dig2 = 12;
        Console.WriteLine("num = {0} dig2 = {1}", num, dig2.val);
        Console.ReadLine();
    }
}
threenewbee 2018-12-20
  • 打赏
  • 举报
回复
用表达式树,我完整写了一个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace T392496087
{
class A
{
public string Str { get; set; }
public int IntVal { get; set; }
}

class B
{
public string str { get; set; }
public int intval { get; set; }
public override string ToString()
{
return string.Format("B str = {0}, intval = {1};", str, intval);
}
}

class Program
{
static List<A> GenAList(int count)
{
List<A> list = new List<A>();
Random rnd = new Random();
for (int i = 1; i <= count; i++)
list.Add(new A { IntVal = rnd.Next(0, 100), Str = "A:" + i.ToString() });
return list;
}

static List<B> HardCoded(List<A> list)
{
return list.Select(x => new B() { intval = x.IntVal, str = x.Str }).ToList();
}

static List<B> ByReflection(List<A> list)
{
var props = typeof(A).GetProperties().Select(x => new { a = x, b = typeof(B).GetProperty(x.Name.ToLower()) });
return list.Select(x => {
B b = new B();
foreach (var item in props)
item.b.SetValue(b, item.a.GetValue(x, null));
return b;
}).ToList();
}

static List<B> ByExpTree(List<A> list)
{
var props = typeof(A).GetProperties().Select(x => new { a = x, b = typeof(B).GetProperty(x.Name.ToLower()) });
var param = Expression.Parameter(typeof(A), "x");
List<Expression> exps = new List<Expression>();
var cre = Expression.New(typeof(B));
var newb = Expression.Variable(typeof(B));
var assb = Expression.Assign(newb, cre);
exps.Add(assb);
foreach (var item in props)
{
var getexp = Expression.MakeMemberAccess(param, item.a);
var setexp = Expression.MakeMemberAccess(newb, item.b);
var ass = Expression.Assign(setexp, getexp);
exps.Add(ass);
}
exps.Add(newb);
var body = Expression.Block(new ParameterExpression [] { newb }, exps);
var sel = Expression.Lambda<Func<A, B>>(body, param);
return list.Select(sel.Compile()).ToList();
}

static void TestIt(string title, Func<List<A>, List<B>> foo, int count, int maxoutput = 5)
{
var listA = GenAList(count);
DateTime dt = DateTime.Now;
var listB = foo(listA);
DateTime dt2 = DateTime.Now;
Console.WriteLine(title);
Console.WriteLine("time spent: " + new TimeSpan(dt2.Ticks - dt.Ticks).TotalSeconds + " sec.");
string omit = "";
if (count <= maxoutput)
maxoutput = count;
else
omit = "...\n";
for (int i = 0; i < maxoutput; i++)
Console.WriteLine(listB[i]);
Console.Write(omit);
}
static void Main(string[] args)
{
int n = 200000;
TestIt("HardCoded", HardCoded, n);
TestIt("ByReflection", ByReflection, n);
TestIt("ByExpTree", ByExpTree, n);
}
}
}



HardCoded
time spent: 0.0390033 sec.
B str = A:1, intval = 74;
B str = A:2, intval = 87;
B str = A:3, intval = 17;
B str = A:4, intval = 93;
B str = A:5, intval = 61;
...
ByReflection
time spent: 0.7790435 sec.
B str = A:1, intval = 43;
B str = A:2, intval = 74;
B str = A:3, intval = 88;
B str = A:4, intval = 84;
B str = A:5, intval = 3;
...
ByExpTree
time spent: 0.0380019 sec.
B str = A:1, intval = 66;
B str = A:2, intval = 6;
B str = A:3, intval = 20;
B str = A:4, intval = 67;
B str = A:5, intval = 52;
...
Press any key to continue . . .
可以看出,性能媲美硬编码,远远超过反射。
  • 打赏
  • 举报
回复
引用 6 楼 足球中国 的回复:
23种设计模式之一,包装模式。
只要是针对”类型转换“设计开发,其实都可以往这上面靠。 还是具体谈 .net 模式更科学更可操作。谈 GOF 设计模式名词儿往往是一个初步的思路。
  • 打赏
  • 举报
回复
比如说“类型转换,例如
public static User Converter2User(IDataRecord rd)
{
    return new User{
        name= (string)rd["name"],
        address=(string)rd["addr"],
        level = 获取组织架构层级((string)rd["department"])
    };
    
这样一个方法,甚至是
var func = new Func<IDataRecord,User>(rd=>
        new User{
          name= (string)rd["name"],
          address=(string)rd["addr"],
        level = 获取组织架构层级((string)rd["department"])
      }); 
就可以用到类似
var result = (from IDataRecord rd in dbcommand.ExecuteReader()
        select Convert2User(rd)).ToList();
或者
var result = (from IDataRecord rd in dbcommand.ExecuteSca()
        select func(rd)).ToList();
这样的代码中。 所以说到性能,不管是静态写一个转换过程,还是动态产生一个委托(#5楼使用 Linq 表达式树动态产生委托函数),总之是类型越强则性能越靠谱。
  • 打赏
  • 举报
回复
总的来说,对于频繁重复操作的优化,原则就是“由弱类型变强类型、由低级动态方式变为预编译缓存形式、由只注重结果变为注重过程”。反射看似高大上,但是往往初级的复杂技术编程方式充其量只能达到刚刚实现功能而已,绕了一大圈反而性能很差。
  • 打赏
  • 举报
回复
引用 6 楼 足球中国 的回复:
23种设计模式之一,包装模式。
其实直截了当地说明了 .net “如何做”的.net模式名词儿,胜过说空洞的GOF模式名词儿。
加载更多回复(8)

13,347

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET技术前瞻
社区管理员
  • .NET技术前瞻社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧