2017-02-14 56 views
0

我知道這個代碼不好,也許這是愚蠢的問題,但任何人都可以解釋爲什麼它以這種方式工作?創建類在行動<T>委託

我有這個簡單的類

public class Customer 
{ 
    public string Name { get; set; } 
} 

而且我有行動的委託下一個方法

private Customer GetCustomer(Action<Customer> action) 
{ 
    var model = new Customer { Name = "Name 1" }; 
    action?.Invoke(model); 

    return model; 
} 

然後我執行該方法與委託和寫入控制檯model.Name

var model = GetCustomer(c => c = new Customer { Name = "Name 2" }); 
Console.WriteLine(model.Name); 

我希望得到「名稱2」。但是我得到了「名稱1」 - 這是方法內部定義的類的值。我明白,要得到我想要的 - 我可以這樣寫代碼:

var model = GetCustomer(c => c.Name = "Name 2"); 
Console.WriteLine(model.Name); 

一切都會好的。但爲什麼我的第一個實現不起作用? 如果有人向我解釋這一點,我會很感激。

+0

方法實例未取代你,你不能這樣做,從拉姆達內。 – Maarten

+0

'c'是'model'的引用的副本。在分配'c = new ...''c'後,將會引用另一個isntance – Fabio

回答

3

c在您的lambda中只分配給參數,它不會將其返回到modelGetCustomer

0
var model = GetCustomer(c => c.Name = "Name 2"); 

代替:

var model = GetCustomer(c => c = new Customer { Name = "Name 2" }); 

爲什麼?因爲您希望對新函數中傳輸的同一實例執行更改(實現委託)。如果您在新功能(c)中創建了一個新實例Customer,那麼它將對Customer的新實例進行更改,當c結束時,該更改將無效。

相同here但與List

+1

他在原始文章中有這個。 –

+1

如果你解釋爲什麼會回答這個問題,這將是一個更好的答案 - 但我認爲你在這裏尋找OP的正確軌道。 –

0

在你的lambda表達式中,你只是說cmodel指向相同的引用。然後你改變c的參考。在末尾model仍然引用到以前的實例。這是你正在嘗試做的等效代碼:

var model = new Customer { Name = "Name 1" }; 
var c = model; 
c = new Customer { Name = "Name 2" }; 

但是,model.Name仍然Name1

,如果你想改變興田屬性之一,您可以更改您的代碼:

var model = GetCustomer(c => c.Name = "Name2"); 
Console.WriteLine(model.Name); 
1

你的情況Lambda表達式編譯成一個方法。
這是一樣的,爲什麼這個代碼不會改變c.Name

// code below is equivalent of 
// c => c = new Customer { Name = "Name 2" } 
private void Foo(Customer c) 
{ 
    // c will be changed inside method, 
    // but will remain unchanged outside it 
    c = new Customer { Name = "Name 2" }; 
}