假设我们有一个像这样的数据进行原生库:值类型到IntPtr的应用程序生命周期中使用
double *pointer = &globalValue;
SetAddress(pointer);
//Then we can change value and write it to disk
globalValue = 5.0;
FlushValues(); // this function writes all values
// registered by SetAddress(..) functions
... //Then we change our value (or values)
FlushValues(); //and do write any time we need
现在我必须把它互操作到C#。我想避免使用不安全的...但是...我不知道=)
所以在C#端我们将有一些我们将写的类。我们能做的事情写,如:
public class Data
{
[Serializable] <-- somehow we mark what we are going to write
double myValue;
...
[Serializable]
double myValueN;
}
public class LibraryInterop
{
IntPtr[] pointers; //Pointers that will go to SetAddressMethod
...
public void RegisterObject(Data data)
{
... //With reflection we look for [Serializable] values
//create a pointer for each and some kind of BindingInfo
//that knows connection of pointers[i] to data.myValueN
//Then add this pointers to C++ library
foreach(IntPtr pointer in pointers) { SetAddress(pointer);}
}
public void Flush()
{
//Loop through all added pointers
for(int i=0; i<pointers.Length; i++)
{
double value = ... //With reflections and BindingInfo we find data.myValueN
// that corresponds to pointers[i]
// then we write this value to memory of IntPtr
// we have to brake value to bytes and write it one by one to memory
// we could use BitConverter.DoubleToInt64Bits() but double - is just
// an example, so in general case we will use GetBytes
int offset = 0;
foreach(byte b in BitConverter.GetBytes(value))
{
Marshal.WriteByte(pointer[i],offset,byte);
offset++;
}
}
//Save values of IntPtr to disk
FlushValues();
}
}
然后用户代码如下所示然后
var library = new LibraryInterop();
var data1 = new Data();
var data2 = new AnotherData();
library.RegisterObject(data1);
library.RegisterObject(data2);
...//change data
library.Flush();
...//change data
library.Flush();
...//change data
library.Flush();
所以在C++中,我们有一个非常整齐的结构。我们有指针,我们填充这些指针后面的数据,并在FlushValues上记录所有这些值。
C#部分不能有SetAddress(ref double值)。由于地址可能会发生变化,我们不得不针对指针 - 使用unsafe + fixed或IntPtr,并且有很多令人头疼的问题。
另一方面,通过将data.myValue装箱为Object,我们可以拥有“托管指针”。因此,如果可以以某种方式将此ValueType data.myValue绑定到IntPtr而没有这种应对和反思 - 它将会更加简洁。
是否有可能做到这一点互操作,并有更少的丑陋和缓慢的C#部分,那么我列在这里?
非常有趣的解决方案。我应该看看它。谢谢! – MajesticRa 2011-06-04 00:01:34
它要求直接呼叫者完全信任。所以它不能被部分信任或透明的代码使用。它不是和普通的美国安全一样吗? – MajesticRa 2011-06-04 00:04:46
@MajesticRa:即使是不安全的代码,实际上也很困难 - 您仍然需要“永久”固定对象,这需要这种技术。 'fixed'只对一段代码有效。 – 2011-06-04 00:10:59