2013-03-16 161 views
3

我正在學習/試用C#中的一些功能模式,並且我碰到了一個我不能解釋的凹凸。我相信這是一個簡單的答案(我希望),但我很難看到它。可能與封閉等有關,我無法擺脫箱子隱藏我的答案!我可以從C#委託中返回對新對象實例的引用嗎?

這裏是我的實驗:我想從一個函數委託中返回一個特定類的品牌新實例..

public class Foo{ 
    string A { get; set ; } 
} 

static void Main(string[] args){ 
    // the delegate... 
    Func<Foo,bool> someFunc = o => { 
     o = new Foo { A = "A new instance of o?" }; 
     return true; 
    }; 

    Foo foo = null; // was hoping to replace this via delegate 
    var myFunc = someFunc; 
    var result = myFunc(foo); 

    if (foo == null) 
     Console.WriteLine("foo unchanged :-("); 
    else 
     Console.WriteLine(foo.A); // hoping for 'A new instance of o?' 

當然,我只是得到「富不變:-(」在我的輸出 我在測試中做了一個細微的變化,我在非空Foo實例中傳遞並修改了屬性「A」(vs返回一個新實例)並且工作正常(也就是說,我可以改變現有對象就像我期望將對象引用傳遞給函數時一樣)我似乎無法從我的代理中獲取新實例。

那麼,我只是在代碼中做錯了什麼?這可以完成嗎?想知道爲什麼這不起作用。

回答

4

您可以返回Foo作爲lambda表達式的返回值:

Func<Foo> someFunc = o => 
{ 
    return new Foo { A = "A new instance of o?" }; 
}; 

或者你可以返回Tuple<bool, Foo>如果你真的需要返回一個bool

​​

或者,如果你真的真的確定你想要的,你可以聲明你自己的自定義Func -like代表與out parameter

delegate TResult FuncOut<T, TResult>(out T arg); 
FuncOut<Foo, bool> someFunc = (out Foo o) => 
{ 
    o = new Foo { A = "A new instance of o?" }; 
    return true; 
}; 

Foo foo; 
var result = someFunc(out foo); 

但我不會建議。

+0

我同意!沒有'out'parms ;-)所以,返回Tuple中的對象是我可能會去的方式。我認爲lazyberezovsky給了我一個關於'爲什麼'的線索,但我將其標記爲答案,因爲你已經給了我'需要的'和''的解決方法。謝謝 – robcom88 2013-03-16 14:52:34

2

您正將Foo對象的引用(即地址)傳遞給您的代理。該地址分配給委託的參數o(將其視爲本地變量)。當您在委託中更改Foo對象時,您將要引用對象並更改該地址上的內容。這就是對象改變的原因。

但是,當您將新地址分配給代理的局部變量(即參數)時,那麼您僅丟失傳遞到委託的原始Foo對象的地址。賦值局部變量之後只保存新的Foo對象的地址。它不影響調用者的foo變量,該變量仍包含另一個地址。

+1

好的,這很有道理。最終,這回答了我的潛在問題,爲什麼我的測試不起作用(希望我能給出部分答案功勞)。我認爲我錯過了這裏的對象引用中的一個基本教訓,這個引導被代表方面所模糊。事實上,即使使用傳統(即非委託)方法,我的測試也不會起作用。感謝幫助! – robcom88 2013-03-16 14:57:37

5

形式參數o拷貝的值foo;突變o不會變異foo。這和你說的一樣:

int x = 1; 
int y = x; 
y = 2; 

這並不改變xyx,而不是一個別名x的值的副本

你正在過問這個問題。如果你想有一個變異本地的委託,然後只寫變異本地的委託:

Foo foo = null; // was hoping to replace this via delegate 
Action mutateFoo =() => { foo = new Foo() { A = "whatever"}; }; 
mutateFoo(); 
if (foo == null) 
    Console.WriteLine("foo unchanged :-("); 
else 
    Console.WriteLine(foo.A); 

如果你想要做的是變異的變量,然後變異的變量。如果您只是想執行副作用,則無需從委託中傳入或傳出任何內容。

我注意到你說你正在試驗功能模式。請記住,功能性編程阻止變異突變,所以你可能會在這裏走錯路。

+0

在你的例子中(使用整數),我明白這適用於_value types_,但如果'x'和'y'是_reference types_,那麼在'y = x'語句之後,我現在不是處理兩個引用同樣的目標?我通過'y'所做的任何更改都會影響'x'。我錯過了那裏的東西嗎? – robcom88 2013-03-16 15:10:37

+0

哦,我知道有人會讓我看到這個功能性評論;-)我明白,當我沿着這條功能性的道路前進時,突變不是答案。良好的接觸和感謝提醒。 – robcom88 2013-03-16 15:11:58

+0

@ robcom88:如果'x'和'y'指向字段爲'z'的同一個對象,那麼'xz'和'yz'指向同一個字段,但'x'和'y'不指向*其他*。它們都指向*相同的對象*。 – 2013-03-16 15:13:00

相關問題