【发布时间】:2014-09-25 02:20:12
【问题描述】:
问题简述:
如何获取作为对象传递给类库的用户定义结构的大小?
概述:
这个测试项目的重点是构建一个类库,该类库使用 .Net 4(或更少)内的内存映射来封装内存共享。最后我希望能够在我的主应用程序中定义一个结构,将它传递给类库包装器并让类库确定结构的大小。
定义:
- MyAppA:主应用程序,将创建内存映射的应用程序 最初的实例。
- MyAppB:用于通信的第二个应用程序 与 MyAppA。这将利用现有的内存映射。
- MemoryMapTool:这将是封装所有内存共享的类库。
- 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();
}
}
}
【问题讨论】:
-
你的
TestStruct根本不是一个结构,而是一个类。并且大小会根据您是作为 64 位还是 32 位应用程序运行而有所不同。 -
是的,卡梅伦,我知道。在最初写下我的问题后,我做出了改变……我从一个结构开始,但由于某种原因无法工作的结构有问题,我不得不把它变成一个类。无法创建它的实例或类似的东西......如果需要,我可以将其设为结构。
-
@leppie 我不知道您为什么编辑我的问题以删除 c#4 标记...这就是我正在使用的框架,并想确保有人没有使用诸如 c 之类的解决方案#4.5+(4.5 内置了一些特殊的东西来帮助我实现我想要做的事情)。
-
@ArvoBowen:您没有特定于 C# 4 的代码。这一切都只是 C#。也许您不想使用 .NET 4.5,但我没有看到任何证据表明答案需要它。如果有,请在您的问题中告诉我们。通过再次阅读您的问题,使用 Remoting 或 WCF 很容易做到这一点。
-
请注意,MemoryMappedFiles 是在 .NET 4.0 中首次引入 C#,因此您将无法定位任何较低版本。
标签: c# memory structure shared-memory