将对象复制到“this” C# 中的对象

发布于 2024-09-08 07:20:08 字数 697 浏览 6 评论 0原文

我有一定的类雇佣关系,需要能够将所有公共属性从一个对象复制到另一个对象。
每个类都有一组特定的公共属性,这些属性可能与任何其他类不同

示例:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

娇女薄笑 2024-09-15 07:20:08

您缺少的是,当您所说的只是 T 是 Base 时,您要求编译器知道 T 可能是类型 D1 和 D2 之一。它怎么可能知道对象的属性甚至类型,因为这些信息仅在运行时才知道。即使您可以foreach (PropertyInfo in this.Properties),它也会在运行时找出这些属性的名称,所以速度和反射一样慢,否则怎么办?它? (它是反射,只是更漂亮的语法)。它无法知道哪些属性是常见的,直到它知道它正在处理什么类型,并且您已经说过“直到运行时我才告诉您”,所以答案是“好吧,我必须查看运行时”,即反射。

其次,仅仅因为 D1 和 D2 可能都具有名为 Size 的属性,并不意味着它们是相同的属性(除非该属性存在于共同的祖先中)。

例如,

  • ArtilleryAmmo.Shell 和
    山核桃壳。
  • AcmeCorp.Staff 和 GandolfTheWizard.Staff
  • California.State 和 MyBrokenEngine.State
  • LoudSpeaker.Volume 和 MassiveCrater.Volume
  • Cave.Bats 和篮球游戏.Bats

等。

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,

  • ArtilleryAmmo.Shell and
    PecanNut.Shell.
  • AcmeCorp.Staff and GandolfTheWizard.Staff
  • California.State and MyBrokenEngine.State
  • LoudSpeaker.Volume and MassiveCrater.Volume
  • Cave.Bats and BasketballGame.Bats

etc. etc.

过气美图社 2024-09-15 07:20:08

您可以使用架构更改来解决此问题,并使用“PropertyBag”来存储每个类的属性。

PropertyBag 本质上是一个 Dictionary,您可以在其中为一段数据命名并将其添加到包中。缺点是所有内容都会转换为 object,因此它不是很类型安全,而且有很多装箱/拆箱,而且在编译时不会检查名称字符串,因此会出现拼写错误持续的威胁。

当您在类上定义属性时,您可以从类的 propertybag 中存储/检索该项目:

public int MyProperty
{
    get
    {
        return (int)_propertyBag["MyProperty"];
    }
    set
    {
        if(_propertyBag.Keys.Contains("MyProperty"))
        {
          _propertyBag["MyProperty"] = value;
        }
        else
        {
          _propertyBag.Add("MyProperty", value);
        }
    }
}

因此,现在要聚合派生类的所有属性,您可以公开它们的“原始”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 to object, 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:

public int MyProperty
{
    get
    {
        return (int)_propertyBag["MyProperty"];
    }
    set
    {
        if(_propertyBag.Keys.Contains("MyProperty"))
        {
          _propertyBag["MyProperty"] = value;
        }
        else
        {
          _propertyBag.Add("MyProperty", value);
        }
    }
}

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.

染火枫林 2024-09-15 07:20:08

Base 类中的 Copy 方法只能访问 Base 类中定义的属性。您可以复制这些属性。

但是,如果不使用反射之类的东西,就无法从子类复制属性。但即使使用反射,您也需要一些有关不同子类之间属性映射的知识,例如将 ID 属性复制到 Name

因此,您需要为每个(允许的)子类转换编写单独的实现。

public interface IBaseCopier<TFrom, TTo> where TFrom : Base, TTo : Base
{
  void Copy(TFrom from, TTo to);
}

public class D1ToD2Copier : IBaseCopier<D1, D2>
{
  public void Copy(D1 from, D2 to)
  {
    // Copy properties from the D1 instance to the D2 instance.
  }
}

您可以在工厂类中注册所有 ICopier 实现。此类将根据类型参数查找复制器的实现。如果某种类型组合没有复制器,即不支持转换,工厂应该抛出异常。

public class CopierFactory
{
  public ICopier<TFrom, TTo> Create<TFrom, TTo>() where TFrom : Base, TTo : Base
  {
    // Look up the ICopier implementation for the given types.
  }
}

编辑

您可以使用MemberwiseClone< /a> 方法创建对象的副本。

public class Base
{
  public static T Copy<T>(T data) where T : Base
  {
    return data.MemberwiseClone() as T;
  }
}

如果您需要对克隆进行更多控制,可以实现 ICloneable 接口< /a>.

注意:您应该意识到,您无法将 D1 实例克隆到 D2 实例中。这就像将羊克隆成马一样。

The Copy method in the Base class only has access to the properties that are defined in the Base 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 to Name.

So you'll need to write separate implementations for each (allowed) subclass conversion.

public interface IBaseCopier<TFrom, TTo> where TFrom : Base, TTo : Base
{
  void Copy(TFrom from, TTo to);
}

public class D1ToD2Copier : IBaseCopier<D1, D2>
{
  public void Copy(D1 from, D2 to)
  {
    // Copy properties from the D1 instance to the D2 instance.
  }
}

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.

public class CopierFactory
{
  public ICopier<TFrom, TTo> Create<TFrom, TTo>() where TFrom : Base, TTo : Base
  {
    // Look up the ICopier implementation for the given types.
  }
}

Edit

You can use the MemberwiseClone method to create a copy of an object.

public class Base
{
  public static T Copy<T>(T data) where T : Base
  {
    return data.MemberwiseClone() as T;
  }
}

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 a D2 instance. That would be like cloning a sheep into a horse.

铜锣湾横着走 2024-09-15 07:20:08

我认为复制方法应该由派生类 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.

-柠檬树下少年和吉他 2024-09-15 07:20:08

我要做的是为基类创建一个扩展方法,例如:

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int CopyTo<T>(this Base source, ref T dest)
        {
          // Use reflection to cycle public properties and if you find equally named ones, copy them.
        }
    }   
}

然后你可以在你的对象中调用它,就像:

  source.CopyTo<ClassType>(ref this);

我没有测试,所以不确定它是否会像描述的那样工作。我在我从事的一个大项目中做了类似将 DataRows 转换为实体的操作。

What I would do is create an extension method for the Base class like:

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int CopyTo<T>(this Base source, ref T dest)
        {
          // Use reflection to cycle public properties and if you find equally named ones, copy them.
        }
    }   
}

Then you could call it in your objects and like:

  source.CopyTo<ClassType>(ref this);

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文