#c# #interop #struct #fortran
#c# #взаимодействие #структура #fortran
Вопрос:
Я могу передать C#
структуру в FORTRAN
просто отлично. Я даже могу передать массив C#
структуры как массив TYPE()
в FORTRAN
. Где я столкнулся с проблемой, так это когда я попытался вернуть значения обратно в C#
. Вот пример:
Библиотека DLL fortran является:
MODULE TESTING
TYPE VALUEREF
INTEGER*4 :: A
ENDTYPE VALUEREF
CONTAINS
SUBROUTINE TEST_REF(T,N)
!DEC$ ATTRIBUTES DLLEXPORT :: TEST_REF
!DEC$ ATTRIBUTES ALIAS:'TEST_REF' :: TEST_REF
!DEC$ ATTRIBUTES VALUE :: N
IMPLICIT NONE
INTEGER*4 :: A,I,N
TYPE(VALUEREF) :: T(N)
A = 100
DO I=1,N
T(I)%A = A I
END DO
END SUBROUTINE
END MODULE
и C#
вызывающая функция, которая ожидает результатов, является:
[StructLayout(LayoutKind.Sequential)]
public struct ValueRef
{
public int a;
}
[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef[] t, int n);
void Main()
{
ValueRef[] T = new ValueRef[4];
for (int i = 0; i < T.Length; i )
{
T[i].a = i;
}
Console.WriteLine("Initialize");
for (int i = 0; i < T.Length; i )
{
Console.WriteLine(" A={0}", T[i].a);
}
Console.WriteLine("Call Fortran");
TEST_REF(T, T.Length);
for (int i = 0; i < T.Length; i )
{
Console.WriteLine(" A={0}", T[i].a);
}
}
С результатами:
Initialize
A=0
A=1
A=2
A=3
Call Fortran
A=0
A=1
A=2
A=3
Отлаживая код FORTRAN, я вижу, что начальные значения передаются из C#
в FORTRAN
просто отлично. Значения переопределяются новыми значениями, и управление передается обратно в C#
где старые значения все еще содержатся в ValueRef
экземплярах.
Почему я могу передавать и возвращать массив float
или int
аналогичным образом, просто отлично. и я могу передавать и возвращать единичные структуры с ref
ключевым словом, и я могу передавать, но не возвращать и массив struct
?
PS. Я использую Compaq Visual Fortran 6.5 и .NET 3.5
PS2. Я ценю любые комментарии / идеи по этому поводу. Я на 95% закончил свой проект, и теперь я сталкиваюсь с этой проблемой. Весь смысл этого проекта в том, чтобы максимально использовать структуры, чтобы уменьшить количество аргументов, передаваемых функциям, и сохранить определенные аспекты проектирования ООП.
Комментарии:
1. Я думаю, это зависит от того, как во время выполнения сортируются ваши значения, это не должно быть проблемой, это всегда работало нормально, я больше всего поражен, увидев гибрид FORTRAN / C #.
2. примечание форматирование обратной ссылки, к сожалению, недоступно в заголовках
3. Реальность такова, что современный FORTRAN прост и быстр. Я не вижу причин, по которым не только сохранять устаревший код, но и разрабатывать новый код на FORTRAN. Конечно, для графического интерфейса и тому подобного я оставляю это C # / OpenTK.
Ответ №1:
Я делал это в прошлом, используя указатель, а не массив. Я думаю, что ваши структуры копируются для вызова P / Invoke:
[DllImport("mathlib.dll")]
static extern void TEST_REF(ValueRef* t, int n);
Вам нужно будет закрепить свой массив перед вызовом метода.
fixed (ValueRef* pointer = t)
{
TEST_REF(pointer, n);
}
Редактировать:
На основе комментариев решение состоит в том, чтобы объявить внешний как
[DllImport("mathlib.dll")]
static extern void TEST_REF([Out] ValueRef[] t, int n);
Вот ссылка MSDN на маршалинг массивов и то, как они используются по умолчанию [In]
.
Комментарии:
1. Я как раз собирался предложить, чтобы … убедитесь, что вы скомпилировали свой код с флагом unsafe и пометили свои методы и область действия ключевым словом unsafe, иначе вы получите кучу ошибок компилятора.
2. Когда я передаю единственную структуру по ссылке, она не копируется, но когда я передаю массив, она копируется!?
3. Вторая вещь, которую вы можете попробовать, — это использовать атрибут [Out] в подписи P / Invoke.
4.
[Out]
Атрибут сработал. поэтому, если вы отредактируете свой ответ, я присужу его.5. Я отредактировал ответ с правильным решением и добавил соответствующую ссылку от Microsoft.