2015-02-10 98 views
0

我有需要有一个类内的私人结构成员,并且正在寻找一种方法来访问此结构成员,而不执行副本。c#结构参考以防止复制

原因是这个结构被用作一个c dll的接口。

public class MyCDllApi 
{ 
    // Marshalled struct 
    [StructLayout(LayoutKind.Sequential)] 
    public struct DllData 
    { 
     [MarshalAs(UnmanagedType.U1)] public byte data1; 
     [MarshalAs(UnmanagedType.U1)] public byte data2; 
     // ... 
     // lots more; this is really a LARGE struct 
    } 

    // DLL Function call 
    [DllImport("MyC.dll", CallingConvention=CallingConvention.Cdecl)] 
    private static extern int do_some_work(ref DllData data); 

    public void doSomeWork() 
    { 
     do_some_work(ref m_dllData); 
    } 
    public DllData getData(); 

    private DllData m_dllData; 
} 

public class MyProg 
{ 
    static void Main(String args[]) 
    { 
     MyC_DllApi m_dllApi = new MyCDllApi(); 
     m_dllApi.doSomeWork(); 
     DllData data = m_dllApi.getData(); 

     // Use data 
    } 
} 

我在想,我可以框结构和的getData()返回一个对象,但是这意味着铸造是必需的。

我也在想,我可以在一个类中包含结构,这可以作为参考传递,但是提供用于检索结构成员的任何方法都会执行副本。

另一个想法是公开m_dllData。

有人能告诉我在这种情况下在C#中的正常解决方案,即相当于在C++中返回“const &”。出于性能原因,我是否想避免创建结构的副本?我可以通过ref传递一个结构作为函数参数。我可以不返回一个类成员结构的ref?

编辑

只是为了澄清,在这种情况下,我使用的是结构,因为这符合DLL的API,我认为这是很好的与这个API是一致的。我不是要求一种方法来替代这个类。同样,我不想找到一个解决方案,使这个类更复杂。

我想让MyCDllApi成为一个简单的非智能c#封装到C DLL。我问是否有任何合理的方法来避免每次外部对象访问此类检索DllData时的结构副本。即以类似于C++中的“const &”的方式。

如果这样的解决方案/模式在C#中不常用或不适合,那么这很好。我的程序可以处理结构副本的开销。我只是想问这个问题。

感谢

+1

该结构太小了,为什么你担心它被复制? – 2015-02-10 16:27:54

+0

您可能希望重新命名您的问题以更好地描述问题。另外,作为一个附注,C#标准是'MethodName()'而不是'methodName()',匈牙利符号有点缺乏。 – 2015-02-10 16:29:24

+0

显示的结构就是一个例子。为了简单起见,我保持小巧。真正的结构非常大。 – user1400716 2015-02-10 16:42:02

回答

2

从评论,这听起来像你有三种选择:

  1. 使用class[SequentialLayout];请参阅MSDN示例。

  2. 不要试图返回getData()中的整个结构,而只是返回调用者真正感兴趣的部分。一个变种就是传递一个Func<>(或Action<>)来对结构进行操作。这两种技术避免复制。

  3. C++在C++中工作;用C++/CLI而不是C#实现doSomeWork()。这也避免了从C#中的.h文件复制(大)结构。

+0

谢谢。我有改变的dll所以不能做选择1.无用武之地我的课的目的是简单的实现C#/ C接口,即提供的包装器的C DLL,并让外部类做更多有意义的工作。我不想为该类的用户提供限制,也不希望在MyCDllApi内部执行任何功能,而不是使用dll作为愚蠢包装。 – user1400716 2015-02-10 17:51:53

+1

@ user1400716:通过p/invoke编组将涉及复制数据,句点。 .NET不会让你的C++在你的脚上拍摄你的C#。你可以像“struct”一样容易地将数据编组为一个'class'; p/invoke并不关心(对于非托管代码,'''和'struct'也具有完全相同的实现)。恕我直言,丹的#3建议可能就像你要达到你想要的目标一样,但是问题中没有足够的细节来确定。 – 2015-02-11 03:28:51

+0

@PeterDuniho:可以通过引用来封送blittable类型;在.NET方面,它们作为'ref'参数传递,而本机方面它们被声明为指针。当.NET通过引用传递一个包含在一个对象字段中的结构体时,该对象将被锁定,直到该方法返回。 – supercat 2015-02-11 22:33:03