果壳中的问题:
如何获得作为对象传递给类库的用户定义结构的大小?
概述:
这个测试项目的目的是构建一个类库,它使用.Net 4(或更少)内存映射来包装内存共享。最后,我希望能够在我的主应用程序中定义一个结构,将其传递给类库包装器,让类库确定结构的大小。
解释
初步想法:
我希望类库包装器不知道MyAppA生成的TestStruct,除了它是类库包装器需要跟上并用于内存共享的对象......
我在想我会在MyAppA中创建TestStruct,并根据需要添加尽可能多的变量(在本例中只是1,一个字符串)。然后将它传递给MemoryMapTool构造函数,让MemoryMapTool类确定struct的大小。这是目前的问题。使用内存我倾向于谨慎和研究之前,我只是尝试一些可能会失败杀死我的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();
}
}
}
答案 0 :(得分:1)
我认为错误非常清楚。您需要告诉CLR您希望结构或类成员如何在内存中布局。请参阅StructLayoutAttribute
- 它需要明确应用于类(而结构Sequential
是默认值。)
根据您的描述,您似乎希望在两个或更多托管进程之间执行IPC。您可能还想为字符串建立统一的编组策略(请参阅MarshalAsAttribute
)。您可以选择一个并在整个课程中坚持使用它。
最后,我想说这不适合你要做的事情(过多的开销和错误的余地)。相反,你可以:
我的选择是#2。性能可以非常好,特别是对于WCF和具有命名管道或net.tcp绑定的同一台计算机,它只是起作用。