使用unsafe是否可以复制类字段?

5
我有两个类。
[StructLayout(LayoutKind.Explicit, Size = 12, CharSet = CharSet.Ansi)]
unsafe class Dto
{
    [FieldOffset(0)]
    public int B;
    [FieldOffset(4)]
    public int C;
    [FieldOffset(8)]
    public int D;
}
[StructLayout(LayoutKind.Explicit, Size = 12, CharSet = CharSet.Ansi)]
unsafe class Model
{
    [FieldOffset(0)]
    public int B;
    [FieldOffset(4)]
    public int C;
    [FieldOffset(8)]
    public int D;
}

有没有办法将DTO实例的字段数据复制到Model实例中? 对于单个字段,我有以下代码
var a1 = new Dto { B = 10, C = 20, D = 30 };
var a2 = new Model();

unsafe
{
     fixed (int* pa1 = &(a1.B))
     {
          fixed (int* pa2 = &(a2.B))
          {
               *pa2 = *pa1;
          }
     }
 }

C#提供类似的方法来复制整个对象吗?逐字段复制不可取,因为这是在高性能环境中。


你的意思是,像c memcpy这样吗? - StuartLC
4
这些应该是普通的结构体。没有必要做任何不安全的操作,只需进行简单的赋值即可。值类型的存在是为了使代码更快,所以请使用它们。 - Hans Passant
2
“逐字段复制不适合高性能环境。” ==> “你有测量过吗?有实际的性能问题吗?” - ken2k
拒绝公共字段 - Sriram Sakthivel
@recursive 来吧,我这里没有看到结构体?我错过了什么吗?那结构体的借口是什么?请教育我一下。 - Sriram Sakthivel
显示剩余4条评论
3个回答

2
您的主要关注点是性能。如果逐个字段复制,这将转化为6条mov指令。很难比此更快。
使用指针不会减少所需的指令数。为什么会呢?你仍然需要相同的赋值。
调用memcpy涉及远比微不足道的6条mov指令更多的开销。
因此,您应该编写“朴素”的三个赋值,使用安全的托管代码来获得最佳性能。事实上,拷贝这个12字节的对象非常便宜,我怀疑您的性能问题是否有效。我怀疑这不会在任何配置文件中显示出来。
对于复制性能,无论您使用class还是struct都没有关系。但是由于其他差异,struct具有某些性能优势。您可能希望进行一些调查。

0

在C#中,最接近memcpy的功能是Buffer.BlockCopy,尽管它是为数组设计的。

这是一个关于此话题的有趣的文章

我认为如果你简化你的代码,删除不安全的部分,只使用普通结构体,可能还可以加上转换运算符,你会对性能感到非常惊讶。

就像这样;

   public struct Model
   {
      public int B;
      public int C;
      public int D;

      public Model(Dto dto)
      {
         B = dto.B;
         C = dto.C;
         D = dto.D;
      }

      static public implicit operator Model(Dto dto)
      {
         return new Model(dto);
      }
   }

这将允许您只需说...

     Dto a1 = new Dto { B = 10, C = 20, D = 30 };

     Model m = a1;

我没有完全描述清楚我的问题,抱歉。将数据从现有实例复制到另一个现有实例也是目标的一部分。 - Alexey.Popov
我不确定我理解你的意思。你能重新表达一下吗? - tooslow
主要目标是实现对象的重用。我有一个DTO池和一个Model对象池。当接收到DTO时,我必须将其复制到Model对象中,并释放到池中。 - Alexey.Popov

-1
如果两个结构体具有相同的布局,您可以像这样强制转换指针并赋值:
var a1 = new Dto { B = 10, C = 20, D = 30 };
var a2 = new Model();

unsafe
{
     fixed (Dto * pa1 = &(a1))
     {
          fixed (Model* pa2 = &(a2))
          {
               *pa2 = *(Model*)pa1;
          }
     }
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接