C# 在两个类实例之间动态复制某些属性
我正在尝试编写一段代码,可以获取同一对象的两个实例,并动态地将一些属性从第一个复制到第二个。一个小小的转变是,我只能通过它们都继承的接口访问对象 我创建了一个C# 在两个类实例之间动态复制某些属性,c#,copy,expression-trees,getter-setter,C#,Copy,Expression Trees,Getter Setter,我正在尝试编写一段代码,可以获取同一对象的两个实例,并动态地将一些属性从第一个复制到第二个。一个小小的转变是,我只能通过它们都继承的接口访问对象 我创建了一个Copyable属性,用于标记可以复制的属性 然后,我使用PropertyInfo.GetMethod和PropertyInfo.SetMethod成功地实现了这一点,但是生成的代码太慢了。与编译时静态分配属性相比,这种方法的速度要慢20倍 下面是我使用纯反射的初始实现 using System; using System.Linq; n
Copyable
属性,用于标记可以复制的属性
然后,我使用PropertyInfo.GetMethod
和PropertyInfo.SetMethod
成功地实现了这一点,但是生成的代码太慢了。与编译时静态分配属性相比,这种方法的速度要慢20倍
下面是我使用纯反射的初始实现
using System;
using System.Linq;
namespace ConsoleApp58
{
interface IInterface
{
int Id { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
class CopyableAttribute : Attribute { }
class Child : IInterface
{
public int Id { get; set; }
[Copyable]
public int CopyableProp { get; set; }
}
class Program
{
static void Main(string[] args)
{
var source = new Child() {Id = 1, CopyableProp = 42};
var target = new Child() {Id = 2, CopyableProp = 0};
CopyProps(source, target);
}
static void CopyProps(IInterface source, IInterface target)
{
var props = target.GetType()
.GetProperties()
.Where(p => p.IsDefined(typeof(CopyableAttribute), false))
.ToArray();
foreach (var prop in props)
{
var value = prop.GetMethod.Invoke(source, new object[] { });
prop.SetMethod.Invoke(target, new [] {value});
}
}
}
}
这是可行的,但速度很慢,所以我决定尝试创建一个表达式树,该树将构建一个lambda,可以调用getter和setter,但是我似乎无法使其工作
然而,我尝试了以下方法,实现依赖于这样一个事实,即我知道从中获取属性的对象的类型
但是,在我的例子中,属性被定义为子类的一部分,我在我的IInterface
中无法访问它们
因此,我在这里问是否有一种(快速)方法可以在两个对象的实例之间复制特定属性的值,方法是仅通过它们的公共接口引用它们您可以通过表达式API生成
操作
。请尝试以下代码:
private static Expression<Action<IInterface, IInterface>> CreateCopyMethod(Type type)
{
var props = type
.GetProperties()
.Where(p => p.IsDefined(typeof(CopyableAttribute), false))
.ToArray();
var s = Expression.Parameter(typeof(IInterface), "s");
var t = Expression.Parameter(typeof(IInterface), "t");
var source = Expression.Variable(type, "source");
var castToSource = Expression.Assign(source, Expression.Convert(s, type));
var target = Expression.Variable(type, "target");
var castToTarget = Expression.Assign(target, Expression.Convert(t, type));
var instructions = new List<Expression>
{
castToSource, castToTarget
};
foreach (var property in props)
{
var left = Expression.Property(target, property);
var right = Expression.Property(source, property);
var assign = Expression.Assign(left, right);
instructions.Add(assign);
}
var lambda = Expression.Lambda<Action<IInterface, IInterface>>(
Expression.Block(
new[] {source, target}, instructions),
s, t);
return lambda;
}
为了提高性能,考虑使用<代码>字典<代码>来缓存已经生成的方法
的实现。我有两个IInterface
实例,它们都是Child
类型。我想从源
实例获取具有可复制
属性的所有属性,并将它们的值复制到目标
实例。我希望尽可能快地完成这项工作。第一个实例是反序列化API请求后的输入。我需要获取某些属性并将它们复制到另一个实例,该实例包含每个属性的某种“默认”值。第二个实例从原始实例获取所需的属性,然后传递给其他业务层以供使用。我不能重用同一个实例,因为它稍后会传递给我无法控制的其他组件,并且它的属性引用可能会被修改。我也不能使用具体的类型,因为其他系统的细节,这不是像一个魅力相关的作品。这正是我需要的。在字典中缓存操作lambda后,性能仅比静态分配慢两倍(2-3)。虽然这并不理想,但仍比正常反射快10倍。我想我可以进一步优化它。谢谢!
IInterface src = new Child
{
CopyableProp = 42
};
IInterface dst = new Child();
var copy = CreateCopyMethod(src.GetType()).Compile();
copy(src, dst);
Console.WriteLine(((Child)dst).CopyableProp); // 42