2012-06-07 64 views
2

我無法在定義lambda表達式的函數中使用引用局部值的lambda表達式來設置結構中的值。如果我理解正確,那麼結構會在lambda函數中按值傳遞,但我希望它通過引用傳遞。我不知道怎麼做。lambda表達式中引用的結構

測試代碼:

public struct partialData 
{ 
    public int foo; 
} 
public struct futureData 
{ 
    public int bar; 
} 

// if you change this to a class, everything works as desired. 
public struct someStruct 
{ 
    public partialData pd; 
    public futureData fd; 
} 
class Apple 
{ 
    private Action<object> toBeSet; 
    public someStruct makeStruct(partialData pd) 
    { 
     someStruct ss = new someStruct(); 
     ss.pd = pd; 

     toBeSet = new Action<object>(
      (futureValue) => ss.fd = (futureData)futureValue 
     ); 
     return ss; 
    } 
    public void futureSet(futureData fd) 
    { 
     toBeSet.Invoke(fd); 
    } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     partialData pd; 
     pd.foo = 1; 
     futureData fd; 
     fd.bar = 2; 
     Apple ap=new Apple(); 
     someStruct ss= ap.makeStruct(pd); 
     ap.futureSet(fd); 
     // I'd like it to be 1,2, it results in 1,0 
     Console.WriteLine("foo is: "+ss.pd.foo + ", bar is: "+ss.fd.bar); 
     Console.In.ReadLine(); 
    } 
} 

注: 結構由別人(和用於互操作)寫的,我不能改變他們的類。我喜歡我當前的設計,所以我希望有一種方法來保持這種設計,但只需讓Action中的結構像一個類一樣。不改變爲類的另一個原因是,一些結構深深嵌套,需要更多的努力來更新,而不是我認爲必要的。

+0

我不假設把它裝成'Object'類型,然後將它重新放回到lambda中就行了,對嗎? (如果不是醜陋的) –

+2

其實,等一下,不管你的'makeStruct'方法本質上是否返回你的「someStruct ss」的副本?所以,即使你可以讓你的lambda目標在方法中聲明實際的「ss」實例,makeStruct的調用者是否會收到一個副本,而不是原始的呢? (可以用'ref'參數解決) –

+0

使用ref沒有修復它,但那是我沒有想過的問題。 – Dale

回答

6

如果你想通過引用傳遞結構,那麼你需要用ref參數(這是不是在一套標準Action<>Func<>)自己的委託類型。

此外,使用Lambda表達式時,編譯器無法推斷類型的refout參數,所以,你必須明確地聲明它們或使用好老匿名委託語法(這看起來非常相似,lambda表達式與聲明類型):

struct S 
{ 
    public int f; 
} 

delegate void DoDelegate(ref S s); 

public static void M() 
{ 
    var s = new S(); 

    DoDelegate delegate2 = (ref S st) => st.f = 5; 
    DoDelegate delegate1 = delegate(ref S st) { st.f = 10; }; 

    delegate1.Invoke(ref s); 
    delegate2.Invoke(ref s); 
} 
+0

這看起來不錯,我會用這個。謝謝。 – Dale

+0

這太糟糕了,沒有真正的語言或框架支持集合暴露自己的方法。可變結構比可變類更安全,並且通常比不可變類更方便,但是類似數組的集合所需的語法允許消費者修改其中包含的結構的字段是非常可怕的。 – supercat

+1

順便說一句,鏈接的問題是不同的,因爲它涉及到lambda函數無法捕獲周圍函數的'ref'或'out'參數,而不是限制lambda函數自己的參數。 – supercat

2

將結構放入持有者類並傳遞持有者類的實例。

public class SomeStructHolder 
{ 
    public someStruct theStruct; 
} 
+0

你不應該使用財產。訪問'theStruct'的getter將始終返回結構的副本,使其修改掉'fd'字段。 –

+0

@ChrisSinclair,當然,修正了 –

+0

好的答案,我只是不想做所有的嵌套結構的東西 - 我認爲委託「感覺」就像我正在尋找的答案 - 解釋爲什麼我改變了接受的答案。 – Dale