gpt4 book ai didi

c# - 获取用于内存映射的结构的大小

转载 作者:太空宇宙 更新时间:2023-11-03 13:18:46 25 4
gpt4 key购买 nike

问题简而言之:

如何获取作为对象传递给类库的用户定义结构的大小?

概述:

此测试项目的重点是构建一个类库,该类库使用 .Net 4(或更少)中的内存映射来包装内存共享。最后,我希望能够在我的主应用程序中定义一个结构,将其传递给类库包装器并让类库确定结构的大小。

定义:

  1. MyAppA:主应用程序,将创建内存映射的应用程序实例最初。
  2. MyAppB:用于通信的第二个应用程序使用 MyAppA。这将利用现有的内存映射。
  3. MemoryMapTool:这将是封装所有内存共享的类库。
  4. TestStruct:这将是 MyAppA 和 MyAppB 中定义的结构,在两个应用程序中完全相同,但可能会不时更改。 MemoryMapTool 在任何时候都不会知道结构布局,它只会将其视为一个对象。

初步想法:

我希望类库包装器不知道 MyAppA 生成的 TestStruct,除了它是类库包装器需要跟上并用于内存共享的对象...

我想我会在 MyAppA 中创建 TestStruct 并根据需要向其中添加尽可能多的变量(在本例中只有 1,一个字符串)。然后将其传递给 MemoryMapTool 构造函数,让 MemoryMapTool 类确定结构的大小。这是目前的问题。在使用内存时,我倾向于谨慎并进行研究,然后再尝试可能无法杀死我的 IDE 或操作系统的东西……;)

我原本打算直接将 TestStruct 传递给 MemoryMapTool 构造函数,但遇到了这个问题......

long lMapSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(oData));

错误:找不到类型或命名空间名称“oData”(是否缺少 using 指令或程序集引用?)

然后我想尝试只使用...

long lMapSize = System.Runtime.InteropServices.Marshal.SizeOf(oData);

... 它似乎可以工作(至少 IDE 喜欢它)。但出于某种原因,我觉得这不是正确的做法。

更新:在尝试之后我得到了一个新的错误...

错误:无法将“MyAppA.Form1+TestStruct”类型编码为非托管结构;无法计算有意义的大小或偏移量。


当前资源

MemoryMapTool.cs 内容

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.MemoryMappedFiles;
using System.Threading;

namespace SharedMemoryWorker
{
public class MemoryMapTool : IDisposable
{
#region Private class variables
private string m_sLastError = "";
private MemoryMappedFile mmf = null;
private string m_sMapName = "";
private object m_oData = null;
#endregion

#region Public properties
public string MapName
{
get
{
return m_sMapName;
}
set
{
m_sMapName = value;
}
}

public object Data
{
get
{
return m_oData;
}
set
{
m_oData = value;
}
}
#endregion

#region Constructor
private MemoryMapTool(string sMapName, object oData)
{
long lMapSize = System.Runtime.InteropServices.Marshal.SizeOf(oData);

try
{
//Save the map name
m_sMapName = sMapName;

//Create new map or use an existing one
//mmf = MemoryMappedFile.CreateOrOpen(m_sMapName, lMapSize);


}
catch (Exception ex)
{
m_sLastError = ex.Message;
throw new NullReferenceException("Error creating new object!");
}
}

public void Dispose()
{
//Deconstructor
}
#endregion

#region Public class methods
public string GetLastError()
{
return m_sLastError;
}
#endregion

}
}

MyAppA、Form1.cs 内容

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyAppA
{
public partial class Form1 : Form
{
#region Public structures
public class TestStruct
{
#region Private class variables
private string m_sTest = null;
#endregion

#region Public properties
public string Test
{
get
{
return m_sTest;
}
set
{
m_sTest = value;
}
}
#endregion
}
#endregion

public Form1()
{
InitializeComponent();
}
}
}

MyAppB、Form1.cs 内容

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace MyAppB
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}

最佳答案

我认为错误很明显。您需要告诉 CLR 您希望结构或类成员如何在内存中布局。查看StructLayoutAttribute - 它需要显式应用于类(而结构 Sequential 是默认值)。

根据您的描述,您似乎想在两个或多个托管进程之间执行 IPC。您可能还想为字符串建立一个统一的编码策略(请参阅 MarshalAsAttribute)。您可以选择一个并在整个类(class)中坚持使用。

最后,我想说的是,这并不真正适合您要尝试执行的操作(太多的开销和出错的空间)。相反,您可以:

  1. 仍然使用 MMF,但使用 binary serialization 序列化您的类甚至 JSON。
  2. 设计基于 WCF 或 WebAPI 的面向服务的架构(现在可以通过 OWIN/Katana 自托管)。
  3. 最终您还可以使用原始 TCP/IP 套接字并为您的应用设计一个小型协议(protocol)。

我的选择是#2。性能可以非常好,尤其是使用 WCF 和在具有命名管道或 net.tcp 绑定(bind)的同一台计算机上,它就可以正常工作。

关于c# - 获取用于内存映射的结构的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25087687/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com