C#将数组指针传递给从特定偏移量开始的函数

时间:2014-12-03 18:00:51

标签: c# arrays pointers porting

我将C ++应用程序移植到C#并遇到一些指针问题。

我想要实现的是传递带有偏移量的数组指针,以便传递的函数可以在数组的正确部分上工作。我不想更改函数的签名以为偏移量添加额外的值。

所以,这是我想用C#传递的C ++代码示例:

void DoSomething( double p[] )
{
    p[0] = 0.4;
    p[1] = 0.4;
}

int main()
{
    double Vector[3];

    Vector[0] = 0.2;
    Vector[1] = 0.2;
    Vector[2] = 0.2;

    DoSomething( &Vector[1] );
}

我怎么能这样做?请记住,我无法通过偏移?

[编辑] 谢谢大家的答案。 首先,我要道歉:复制代码时犯了一个大错误。

我写了

DoSomething( Vector[1] );

在最后一行而不是

DoSomething( &Vector[1] );

这已得到纠正。

然后我意识到我对签名不是很清楚。

  • 我可以略微更改函数的签名,但我无法添加任何参数

  • 我已经在使用"不安全"和#34;固定"关键字,所以它不会伤害我

  • 它不需要是高效的代码,因为这个移植是一个快速的&由其他人为原型项目编写的算法的脏实现。如果项目是" Ok go",代码将被抛出垃圾并在C ++ dll中重写。

  • 功能" DoSomething"实际上它是一些其他函数的嵌套,它被设计为一个快速的数学工作但遗憾的是,我不具备自己编写代码的所有知识。这就是为什么我认为作者已经很好地设计了它的功能,因为它在世界范围内被广泛使用。

我会尝试使用Servy的建议,并在我回来的几天内回复你。

4 个答案:

答案 0 :(得分:1)

在不改变DoSomething的签名的情况下不可能,但是你可以避免需要传递两个数组并且它在整个地方并排偏移。您可以通过创建一个组成数组的类来跟踪偏移量来实现:

public class ArrayReference<T> : IEnumerable<T>
{
    //you can keep these entirely private if you prefer
    public T[] Array { get; private set; }
    public int Offset { get; private set; }
    public ArrayReference(T[] array, int offset)
    {
        Array = array;
        Offset = offset;
    }

    public T this[int index]
    {
        get
        {
            return Array[index + Offset];
        }
        set
        {
            Array[index + Offset] = value;
        }
    }

    public int Length
    {
        get
        {
            return Array.Length - Offset;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = Offset; i < Array.Length; i++)
            yield return Array[i];
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public static ArrayReference<T> operator +(
        ArrayReference<T> reference, int offset)
    {
        return new ArrayReference<T>(reference.Array, reference.Offset + offset);
    }

    public static ArrayReference<T> operator -(
        ArrayReference<T> reference, int offset)
    {
        return new ArrayReference<T>(reference.Array, reference.Offset - offset);
    }

    public static implicit operator ArrayReference<T>(T[] array)
    {
        return new ArrayReference<T>(array, 0);
    }
    public static implicit operator T[](ArrayReference<T> reference)
    {
        return reference.ToArray();
    }
}

您可能希望根据您的特定需求为此添加其他功能。您可以根据需要或希望公开底层数组的功能。

答案 1 :(得分:-1)

这实际上不是你在C#中的方式。

执行此操作的唯一方法是使用不安全的代码,即使这样也不是一个好的实现,因为您的方法不安全,并且您的数组必须是fixed

fixed关键字会阻止您的数组被垃圾收集器移动到内存中的其他位置,但它可能会导致内存分区,从而导致性能下降。

此外,即使按设计这也不是一件好事,因为你不知道你方法中的数组边界。

但如果你真的想这样做,请选择调查员。

在您的主要方法中:

double[] d = new double[3];
d[0] = 1.0;
d[1] = 2.0;
d[2] = 3.0;

IEnumerator<double> e = d.AsEnumerable().GetEnumerator();
e.MoveNext();
tryEnumerate(e);

然后是您的DoSomething方法:

static void DoSomething(IEnumerator<double> e)
{
    while(e.MoveNext())
        Console.WriteLine(e.Current.ToString());
}

答案 2 :(得分:-1)

最好的解决方案是从c ++代码构建一个dll,这样我就可以在C#中使用该函数而无需修改签名。

在C#项目中使用dll:

using System.Runtime.InteropServices;

namespace MyDLL
{
    public class TestLib
    {
         [DllImport( "name_of_your_dll" )]
        public static extern DoSomething( double p[] );
    }
}

答案 3 :(得分:-3)

更新代码以使用扩展方法显示链接。您可以轻松返回任何和所有更改并更新所需的任何内容。

List<double> Vector;
Vector.Add(0.2);
Vector.Add(0.2);
Vector.Add(0.2);
DoSomething(Vector.GetRange(index,count));

如果您需要维护原始列表,请执行以下操作:

public static List<double> GetRange(static List<double> list, int index, int count){
     return list.GetRange(Index,Count);
}
public static List<double> DoSomething(static List<double> list){
     //do something here
}

像这样使用:

OriginalList().GetRange(Index,Count).DoSomething();