Допустим, у нас есть собственная библиотека, которая работает с такими данными:
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 value).Поскольку адрес может измениться, мы должны закрепить указатели - использовать unsafe + fixed или IntPtr, и у нас будет SO много головной боли.
С другой стороны, мы можем иметь «управляемые указатели», помещая в коробку | unboxing data.myValue в Object.Поэтому, если бы можно было как-то связать этот ValueType data.myValue с IntPtr без этого копирования и отражения - это было бы намного лучше.
Возможно ли сделать это взаимодействие и иметь менее уродливую и медленную часть C #, чем та, которую я перечислил здесь?