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

时间:2014-08-01 19:51:57

标签: c# memory structure shared-memory

果壳中的问题:

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

概述:

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

解释

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

    我希望类库包装器不知道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();
            }
        }
    }
    

1 个答案:

答案 0 :(得分:1)

我认为错误非常清楚。您需要告诉CLR您希望结构或类成员如何在内存中布局。请参阅StructLayoutAttribute - 它需要明确应用于类(而结构Sequential是默认值。)

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

最后,我想说这不适合你要做的事情(过多的开销和错误的余地)。相反,你可以:

  1. 仍然使用MMF,但使用binary serialization或甚至JSON序列化您的类。
  2. 基于WCF或WebAPI设计面向服务的体系结构(现在可以通过OWIN / Katana进行自我托管)。
  3. 最终,您也可以使用原始TCP / IP套接字,并为您的应用设计一个小协议。
  4. 我的选择是#2。性能可以非常好,特别是对于WCF和具有命名管道或net.tcp绑定的同一台计算机,它只是起作用。