2014-12-03 42 views
-1

我將一個C++應用程序移植到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]); 

然後我意識到我對簽名不太清楚。

  • 我可以稍微改變功能的簽名,但

  • 我已經使用了「不安全」和「固定」的關鍵字我不能添加任何參數,因此它不會傷害我

  • 它不需要是有效的代碼,因爲這個移植的目的是成爲一個快速&其他人爲一個原型項目編寫的算法的髒實現。如果項目是「OK」,則代碼將拋出垃圾並在C++ dll中重寫。

  • 函數「DoSomething」實際上是一些其他函數的嵌套,它被設計成一個快速的數學工作,但遺憾的是,我沒有所有的知識來編寫它自己。這就是爲什麼我認爲作者已經很好地設計了它的功能,因爲它在世界範圍內使用。

我會嘗試使用Servy的建議,幾天後我會回來給你回覆。

+0

這是非常ç差++代碼。我會自己使用一個枚舉器。 – IdeaHat 2014-12-03 18:08:10

+0

我同意IdeaHat和Yakk。在C++'DoSomething'中寫'p [3] = 0.4;'是可能的。你怎麼知道數組的邊界? – Sjips 2014-12-03 18:10:53

+0

你可以像這樣使用LINQ:var filtered = Vector.GetRange(index,count)....將矢量數組更改爲列表 2014-12-03 18:13:44

回答

-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[]); 
    } 
} 
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

是的,製作新的對象類型是C#解決此問題的方式。就個人而言,我認爲只要改變'DoSomething()'函數會更容易。但每一個他自己。 – Hogan 2014-12-03 18:17:31

+0

請注意,這會更改方法的簽名,就像傳遞偏移量一樣。 – 2014-12-03 18:18:48

+0

@Hogan對於這個非常簡單的例子,在數組中傳遞一個偏移量可能很簡單,當然,但是在一個非常複雜的程序中,並且處理大量不斷變化的偏移量的數組,它實際上是合理的將所有用於管理具有偏移量的數組邏輯的邏輯封裝到類中。 OP的* real *問題是否合適複雜以保證這是他需要爲自己做出的決定。 – Servy 2014-12-03 18:19:23

-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(); 
+0

這不起作用DoSomething更改了數組的元素 - 這隻會改變副本。 – Hogan 2014-12-03 18:16:21

+0

這是創建列表的副本。對該副本的更改不會影響原始列表。 – Servy 2014-12-03 18:16:25

+0

查看更新的代碼 – 2014-12-03 21:19:19

-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()); 
} 
+1

首先,您確實想在此使用「IEnumerable」,而不是「IEnumerator」,其次,這將是數據結構的只讀視圖;他的意圖是改變數據。 – Servy 2014-12-03 18:23:12