2009-09-10 95 views
11

我該如何在C#中實現自己的延遲執行機制?在C#中推遲執行#

因此,舉例來說,我有:

string x = DoFoo(); 

是否有可能進行一些魔術,使DoFoo不執行,直到我「用」 X?

回答

17

您可以使用lambda表達式/代表:

Func<string> doit =() => DoFoo(); 
// - or - 
Func<string> doit = DoFoo; 

之後你可以調用doit就像一個方法:

string x = doit(); 

我認爲你可以得到最接近的是這樣的:

Lazy<string> x = DoFoo; 

string y = x; // "use" x 

有了類似這樣的Lazy<T>定義(未經測試):

public class Lazy<T> 
{ 
    private readonly Func<T> func; 
    private bool hasValue; 
    private T value; 

    public Lazy(Func<T> func) 
    { 
     this.func = func; 
     this.hasValue = false; 
    } 

    public static implicit operator Lazy<T>(Func<T> func) 
    { 
     return new Lazy<T>(func); 
    } 

    public static implicit operator T(Lazy<T> lazy) 
    { 
     if (!lazy.hasValue) 
     { 
      lazy.value = lazy.func(); 
      lazy.hasValue = true; 
     } 
     return lazy.value; 
    } 
} 

不幸的是,它似乎是編譯器的類型推理算法不能自動推斷Func<T>的類型,所以不能將其匹配到隱式轉換運算符。我們需要顯式聲明委託的類型,這使得賦值語句更詳細:

// none of these will compile... 
Lazy<string> x = DoFoo; 
Lazy<string> y =() => DoFoo(); 
Lazy<string> z = delegate() { return DoFoo(); }; 

// these all work... 
Lazy<string> a = (Func<string>)DoFoo; 
Lazy<string> b = (Func<string>)(() => DoFoo()); 
Lazy<string> c = new Func<string>(DoFoo); 
Lazy<string> d = new Func<string>(() => DoFoo()); 
Lazy<string> e = new Lazy<string>(DoFoo); 
Lazy<string> f = new Lazy<string>(() => DoFoo); 
+0

但除了額外的間接層之外,「string x = doit()'」與string x = DoFoo()'「有什麼不同? – LukeH 2009-09-10 01:14:27

+0

它不是。我沒有讀到這個問題。將在第二秒內改進答案... – dtb 2009-09-10 01:15:38

+0

在x被「使用」之前,仍然會調用「DoFoo()」。 – 2009-09-10 01:15:58

0

爲什麼不直接調用'DoFoo()'直到你想要?

- 編輯

我的意思是,你是什麼意思「使用」

例如,如果你想讓它'的ToString()調用的時候被調用,您可以隨時繼承類並在那裏實現你的功能(但這將是非常不直觀的恕我直言)。

1

不是傳遞一個字符串X的,傳遞採購你的字符串

Func<String> fooFunc=()=>DoFoo(); 
0

你漂亮的委託很多描述LINQ的行動。 linq查詢描述瞭如何獲取數據,但只有在迭代查詢時纔會檢索數據(調用DoFunc)。考慮如果您可以將您的設計更改爲接受IQueryable<string>,而您需要string

3

雖然它有點髒,你總是可以使用yield關鍵字:

public IEnumerable<int> DoFoo() { 
    Console.WriteLine("doing foo"); 
    yield return 10; 
} 

[Test] 
public void TestMethod() 
{ 
    var x = DoFoo(); 
    Console.WriteLine("foo aquired?"); 
    Console.WriteLine(x.First()); 
} 
6

一種選擇是使用Lazy<T>類,以前從並行擴展庫現在.Net框架4.0的一部分。

它可以讓你在一個線程知道地拖延處理數據。

+0

我更喜歡使用系統類來這樣做。但是,系統類沒有實現隱式運算符,這促使我搜索原因。我發現[this](http://netvignettes.wordpress.com/2011/04/24/implicit-conversion-operators-are-bad/),這就解釋了原因。 – 2014-09-24 21:54:22