非零索引数组

5
我已经创建了一个由LabVIEW编译的.NET库,其中包含一个函数,该函数接受数字数组和乘数。此函数将返回一个数组,其中每个数字都已乘以乘数。当在C#中调用该函数时,发现该函数需要一个非零索引数组(double[*])和一个int作为参数,并返回另一个非零索引数组。
我可以使用C#的Array.CreateInstance()方法创建非零索引数组。但是,由于所需的数据类型是double[*],因此无法将此数组传递到函数中。
从互联网上的研究来看,似乎.NET不支持非零索引数组类型。我已尝试找到修改LabVIEW程序以生成接受零索引数组的函数的方法,但未成功。
有关如何解决此问题的任何建议吗?
更新1
LabVIEW块图 LabVIEW block diagram C#程序
const int Length = 5;
const int LowerBound = 1;
// Instanstiate a non-zero indexed array. The array is one-dimensional and
// has size specified by Length and lower bound specified by LowerBound.
Array numbers = Array.CreateInstance(typeof(double), new int[] { Length }, new int[] { LowerBound });
// Initialize the array.
for (int i = numbers.GetLowerBound(0); i <= numbers.GetUpperBound(0); i++)
{
    numbers.SetValue(i, i);
}

var variable = LabVIEWExports.Multiply(numbers, 2); // This is invalid as numbers is not typed double[*].
Console.ReadKey();

LabVIEW函数在C#中的签名

enter image description here

更新2

尝试使用C#的反射调用LabVIEW函数,但遇到了TargetInvocationException异常。

const int Length = 5;
const int LowerBound = 1;
const string methodName = "MultiplyArray";
const string path = @"C:\";

Array numbers = Array.CreateInstance(typeof(double), new int[] { Length }, new int[] { LowerBound });
for (int i = numbers.GetLowerBound(0); i <= numbers.GetUpperBound(0); i++)
{
    numbers.SetValue(i, i);
}

Assembly asm = Assembly.LoadFile(path + "LabVIEW.Interop.dll");
Type type = asm.GetType("LabVIEW.Interop.LabVIEWInteropExports");

if (type != null)
{
    MethodInfo methodInfo = type.GetMethod(methodName);

    if (methodInfo != null)
    {
        object result = methodInfo.Invoke(methodInfo, new object[] { array, multiplicand }); // Throw exception.
    }
}
Console.ReadKey();

内部异常消息

无法将类型为 'System.Double[*]' 的对象转换为类型 'System.Double[]'。

内部异常堆栈跟踪

在 NationalInstruments.LabVIEW.Interop.DataMarshal.InitMarshalArrayIn(IntPtr data, Array array, Marshal1DArray val) 中, at LabVIEW.Interop.LabVIEWInteropExports.MultiplyArray(Double[*] input__32Array, Int32 numeric)

在执行过程中,程序似乎尝试使用LabVIEW附带的程序集中的InitMarshalArrayIn()函数将类型为double[*]的数据转换为double[]


@Nishat:请不要在非代码内容中使用代码块... - Patrick Hofman
1
.NET支持非零索引的数组。C#没有语法来编写这种类型,但您可以使用Array.Create*创建它,并使用反射传递它。 - usr
1
@MathuSumMut,double[*]是一种类型为double非零索引数组。https://social.msdn.microsoft.com/Forums/en-US/e6f84f77-1a09-4dd9-a2af-eb3a54e9c7bc/array-question-single-dimension-array-with-nonzero-lower-bound?forum=csharplanguage - Noctis Tong
@MathuSumMut,包含LabVIEWExports类的程序集是我自己编写的。块图与我更新问题中的屏幕截图完全相同。它是使用LabVIEW 2015编译为.NET互操作程序集。 - Noctis Tong
我希望重写这个问题,以删除LabVIEW方面。这个问题与LV没有什么具体关系,而且这是一个有用的问题:“C#如何调用其签名中有非零索引数组的库?”是的,LV创建了该签名,但这与手头的问题无关。它可以是任何.NET编译器创建DLL。 - srm
显示剩余5条评论
3个回答

3

.NET支持非零索引的数组。虽然C#没有语法可以直接定义这种类型,但是你可以使用Array.CreateInstance来创建。

接下来,使用反射调用LabVIEWExports.Multiply并传递你创建的数组。


尝试使用反射调用LabVIEWExports.Multiply(请参见问题中的更新2),但遇到异常。我不太确定是我做错了,还是仅仅因为LabVIEW本身不支持从double [*]转换为double [] - Noctis Tong

3

我不确定是否应该将这个作为答案,但是我还是要说一下:

这个问题与Visual Studio 2015有关,因为我正在使用Visual Studio Community 2015 Update 1。更多信息请参见thisthis


1

如果使用dynamic(而不是使用反射),像以下代码的最后一行那样,它会起作用吗:

const int Length = 5;
const int LowerBound = 1;
// Instanstiate a non-zero indexed array. The array is one-dimensional and
// has size specified by Length and lower bound specified by LowerBound.
var numbers = Array.CreateInstance(typeof(double), new int[] { Length }, new int[] { LowerBound });
// Initialize the array.
for (int i = numbers.GetLowerBound(0); i <= numbers.GetUpperBound(0); i++)
{
    numbers.SetValue(i, i);
}

var variable = (Array)LabVIEWExports.Multiply((dynamic)numbers, 2);

变量numbers在C#中具有编译时类型Array,因为C#没有double[*]的语法。但也许使用dynamic会没问题,运行时实际类型应该是正确的,所以可能晚绑定到正确的方法会起作用?

对我不起作用,运行时抛出“System.InvalidCastException”异常。 - Noctis Tong
@NoctisTong 好的。我没有安装新版C#编译器的VS2015,也没有CLR 4.6版本,但是或许这和你在使用反射(更新2)时看到的问题是一样的?从你提供的链接页面中,我得出的印象是在VS2013等版本中它曾经可以正常工作。 - Jeppe Stig Nielsen
@Jeppee,我已经尝试从VS 2010调用由LabVIEW生成的相同程序集,并且它可以工作。看起来这是一个VS问题,而不是LabVIEW问题。 - Noctis Tong
@NoctisTong 是在同一台机器上吗?我问这个问题是因为我们想知道这是否是由C#编译器生成的IL代码问题,还是CLR(运行时)的问题。如果是前者,那么可能是C#编译器输出了一些错误的IL代码,强制执行了一个double[*](也称为double[...])无法通过的检查。如果是后者,那么可能是版本4.6运行时中的一个bug。您尝试过在Visual Studio 2015中将C#目标版本更改为C# 5.0吗?就像这篇文章中所述。 - Jeppe Stig Nielsen
是的,它在同一台机器上。将C#目标版本更改为C# 3.0、C# 4.0和C# 5.0并不能解决这个问题。 - Noctis Tong
1
@NoctisTong 我的假设是,这是VS2015的C#编译器中的一个错误,即使我们针对早期的C#版本(并仍然使用VS2015的C#编译器),它也不会消失。您可以打开ildasm并打开由VS2015生成的EXE/DLL,浏览到相关的方法,并阅读IL以查看是否提到了float64[]或类似内容(这将导致崩溃,因为该实例不是“向量”float64[],而是“一维多维数组”float64[...])。 - Jeppe Stig Nielsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接