将对象复制到“this” C# 中的对象
我有一定的类雇佣关系,需要能够将所有公共属性从一个对象复制到另一个对象。
每个类都有一组特定的公共属性,这些属性可能与任何其他类不同。
示例:
class Base
{
// Common properties/methods...
public void Copy<T>(T data) where T : Base
{
// ...
}
}
class D1 : Base
{
public int ID
{
get;
set;
}
}
class D2 : Base
{
public string Name
{
get;
set;
}
}
通过谷歌搜索,我读到了这些方法:
- 使用反射
- 生成 IL 代码
- 序列化
所有这些方法要么非常复杂,要么非常慢,有时两者兼而有之。
我错过了什么吗?还有其他方法可以访问原始 this
指针吗?
编辑:
我会澄清的。
T 是调用类的类型。例如,如果它是由 D1 调用的,那么 T 将始终是 D1。
通用的原因是我无法真正知道 T 是什么。
我错过了什么吗?
我应该只使用 Base data
作为参数吗?
I have a certain hirerchy of classes that needs the capeability to copy all public properties from one object to another.
Each class has a certain set of public properties that might differ from any other class.
Example:
class Base
{
// Common properties/methods...
public void Copy<T>(T data) where T : Base
{
// ...
}
}
class D1 : Base
{
public int ID
{
get;
set;
}
}
class D2 : Base
{
public string Name
{
get;
set;
}
}
Through googling I have read about those methods:
- Using reflection
- Generating IL code
- Serialization
All of them are either very complex or very slow or sometimes both.
Am I missing something? Is there any other way to access the raw this
pointer?
EDIT:
I will clerify.
T is of the type of the calling class. For example if it was called by D1 T will always be D1.
The reason for the generic is that I can't really know what T is.
Am I missing something?
Should I just use Base data
as the parameter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您缺少的是,当您所说的只是 T 是 Base 时,您要求编译器知道 T 可能是类型 D1 和 D2 之一。它怎么可能知道对象的属性甚至类型,因为这些信息仅在运行时才知道。即使您可以去
foreach (PropertyInfo in this.Properties)
,它也会在运行时找出这些属性的名称,所以速度和反射一样慢,否则怎么办?它? (它是反射,只是更漂亮的语法)。它无法知道哪些属性是常见的,直到它知道它正在处理什么类型,并且您已经说过“直到运行时我才告诉您”,所以答案是“好吧,我必须查看运行时”,即反射。其次,仅仅因为 D1 和 D2 可能都具有名为 Size 的属性,并不意味着它们是相同的属性(除非该属性存在于共同的祖先中)。
例如,
山核桃壳。
等。
What you're missing is that you're asking the compiler to know that T might be one of the types D1 and D2 when all you've said is that T is a Base. How could it possible know what properties or even type your object is as that information is only known at runtime. Even if you could go
foreach (PropertyInfo in this.Properties)
it's going to find out the name of those properties at runtime so be just as slow as Reflection because how else can it? (it is reflection, just prettier syntax). It can't know what properties are common until it knows what types it's dealing with and you've said "i'm not telling you until runtime" so the answer is "well I'll have to look at runtime" i.e. reflection.Secondly, just because D1 and D2 might both have a property named Size doesn't mean they are the same property (unless that property is present in a common ancestor).
For example,
PecanNut.Shell.
etc. etc.
您可以使用架构更改来解决此问题,并使用“PropertyBag”来存储每个类的属性。
PropertyBag 本质上是一个
Dictionary
,您可以在其中为一段数据命名并将其添加到包中。缺点是所有内容都会转换为object
,因此它不是很类型安全,而且有很多装箱/拆箱,而且在编译时不会检查名称字符串,因此会出现拼写错误持续的威胁。当您在类上定义属性时,您可以从类的 propertybag 中存储/检索该项目:
因此,现在要聚合派生类的所有属性,您可以公开它们的“原始”PropertyBag 并迭代它。
正如我之前所说,PropertyBags 不是类型安全的,因此如果层次结构中有两个具有相同属性名称但类型不同的类,那么您就会遇到麻烦。
编辑:如果您关心性能,您将必须以多种方式实现这一点并对不同的实现进行性能测试——我不能诚实地说 PropertyBag 实际上是否比使用反射更快。
You could work around this using an architectural change and use a 'PropertyBag' to store each class' properties.
A PropertyBag is essentially a
Dictionary<string, object>
where you can give a piece of data a name and add it to the bag. The disadvantage is that everything gets cast toobject
, so it isn't very type safe plus there's lots of boxing/unboxing, plus the strings as names don't get checked at compile time, so typos are a constant threat.When you define a property on the class, you store/retrieve the item from the class' propertybag:
So now to aggregate all the properties of the derived classes, you can expose their 'raw' PropertyBag and iterate through it.
Like I said before, the PropertyBags aren't type-safe, so it you have two classes in the hierarchy with the same property name but different type then you're getting into trouble.
EDIT: If you're concerned with performance, you're going to have to implement this multiple ways and perf test the different implementations -- I can't honestly say if a PropertyBag will actually be faster than using reflection.
Base
类中的Copy
方法只能访问Base
类中定义的属性。您可以复制这些属性。但是,如果不使用反射之类的东西,就无法从子类复制属性。但即使使用反射,您也需要一些有关不同子类之间属性映射的知识,例如将
ID
属性复制到Name
。因此,您需要为每个(允许的)子类转换编写单独的实现。
您可以在工厂类中注册所有
ICopier
实现。此类将根据类型参数查找复制器的实现。如果某种类型组合没有复制器,即不支持转换,工厂应该抛出异常。编辑
您可以使用MemberwiseClone< /a> 方法创建对象的副本。
如果您需要对克隆进行更多控制,可以实现 ICloneable 接口< /a>.
注意:您应该意识到,您无法将
D1
实例克隆到D2
实例中。这就像将羊克隆成马一样。The
Copy
method in theBase
class only has access to the properties that are defined in theBase
class. You can copy these properties.But you cannot copy the properties from the subclasses without using something like reflection. But even with reflection you need some kind of knowledge about the mapping of the properties between different subclasses, like copying the
ID
property toName
.So you'll need to write separate implementations for each (allowed) subclass conversion.
You can register all the
ICopier<TFrom, TTo>
implementations in a factory class. This class will look up the implementation of the copier, based on the type arguments. If there is no copier for a certain type combination, i.e. the conversion is not supported, the factory should throw an exception.Edit
You can use the MemberwiseClone method to create a copy of an object.
If you need more control over the cloning, you can implement the ICloneable interface.
Note: You should realize that you cannot clone a
D1
instance into aD2
instance. That would be like cloning a sheep into a horse.我认为复制方法应该由派生类 D1、D2 继承,并且它们有责任将自己的属性复制到其他类型或从其他类型复制自己的属性。
I think the copy method should be inherited by derived classes D1,D2 and their responsibility to copy their own properties to/from other types.
我要做的是为基类创建一个扩展方法,例如:
然后你可以在你的对象中调用它,就像:
我没有测试,所以不确定它是否会像描述的那样工作。我在我从事的一个大项目中做了类似将 DataRows 转换为实体的操作。
What I would do is create an extension method for the Base class like:
Then you could call it in your objects and like:
I didn't test, so not sure if it would work exactly like described. I did something similar to Cast DataRows into Entities in a big project I worked on.