2010-08-01 50 views
4

我正在研究一種需要在不同位置重複小操作的方法,但要重複的代碼應該是該方法的私有方法。顯而易見的解決方案是嵌套功能。無論我嘗試的是什麼,C#編譯器barfs在我身上。如何使一個方法的私有功能?

東西大致等於該Perl的片段:

my $method = sub { 
    $helper_func = sub { code to encapsulate }; 

    # more code 

    &$helper(called whenever needed); 

    # more code 
} 

就是我說的,和我想要在C#來完成。

該類中沒有其他方法應該能夠訪問此上下文中的幫助函數。寫這個結構在C#中,因爲在我看來,最合理的辦法是這樣的:

var helper = (/* parameter names */) => { /* code to encapsulate */ }; 

,實際上使編譯器物盡其。

由於這樣的分配是禁止,由於是使用較舊的代表(){}語法代替拉姆達的等效,因此是一種方法—什麼CSC實際上允許我寫內聲明一個委託類型然而,就是這樣的:

private delegate /* return type */ Helper(/* parameters */); 
private /* return type */ method(/* parameters */) { 

    Helper helper = (/* parameter names */) => { 
     /* code to encapsulate */ 
    }; 

    // more code 

    helper(/* called whenever needed */); 

    // more code 
} 

這是所有罰款和花花公子不拷貝和粘貼一段代碼,並手工編輯的參數,但是它泄漏私人委託類型的類的其餘部分,而不是保持它私有的方法。這首先破壞了目的。使用goto語句和局部變量參數可以在不犧牲代碼重用的情況下,更好地封裝「helper」。如果我想通過通過寄存器傳遞參數來模擬函數調用,我認爲寧願使用匯編器。我還沒有找到一種可以接受的重構代碼的方法來完全避免這個問題。

那麼,是否可以強制這Common Object Oriented Language服從?

+1

「Action」或通用版本呢? – 2010-08-01 16:01:47

+0

看起來我從來沒有聽說過System.Action和System.Func的道歉!看看MSDN,似乎我一定錯過了C#3.5中的一些新功能:-)。 – TerryP 2010-08-01 16:34:38

+0

NET3.5或C#3.0(可能只是爲了混淆每一個) – 2010-08-01 18:41:32

回答

6

如果您使用的是C#3.5或更高版本,則可以利用lambdas和便利代理聲明Func<>Action<>。因此,例如

void DoSomething() 
{ 
    Func<int,int> addOne = (ii) => ii +1; 
    var two = addOne(1); 
} 

的原因,你不能

var addOne = (ii) => ii +1; 

是因爲Homoiconicity,拉姆達可以被解釋爲兩個不同的結構,委託和表達式樹。因此需要在聲明中明確。

+0

作爲同行之間的答案被接受,因爲它記錄了「3.5或更高」,這對於其他任何人通過搜索來絆倒這個問題都是有用的。 – TerryP 2010-08-01 16:42:39

+0

爲所有意圖和目的,你是對的,但嚴格來說(或在看IL時),這是一種炫酷的方式來聲明一個類字段,存儲一個委託和調用它,所以當看着IL它不會被隱藏掩蓋的名稱,但不隱藏) – 2010-08-01 16:53:43

+0

Btw:在C#2.0中的訣竅是使用匿名代表而不是Lambda表達式 – 2010-08-01 17:05:15

-1

其實很簡單。由於該方法似乎有另一個責任比你當前的類(爲什麼你會隱藏這種方法)將你的方法移入它自己的類和你想要私有的部分到新類的私有方法中。

+0

「你的編譯器有這麼小的委託問題,所以你應該完全改變你的設計。」 – zneak 2010-08-01 16:04:00

+0

將與當前類無關的方法移入它自己的類中,實際上是一種很好的設計,並沒有那麼大的改變。試圖強制解決方案而不重新考慮方法是更糟的決定。 – dbemerlin 2010-08-01 16:06:24

+0

你怎麼能推斷出關於一個方法和一個你什麼都不知道的類的大量信息?我不認爲你需要質疑OP的設計有效性,這是一個關於編譯器功能的簡單問題。 – zneak 2010-08-01 16:14:34

8

你實際上可以在C#中做到這一點。

Func<T1, T2, ..., TReturn> myFunc = (a, b, ...) => 
{ 
    //code that return type TReturn 
}; 


如果需要返回類型爲void用行動而不是Func鍵的匿名方法:

Action<T1, T2, ...> myAction = (a, b, ...) => 
{ 
    //code that doesn't return anything 
}; 
+0

+1 http://en.wikipedia.org/wiki/Closure_(computer_science) – 2010-08-01 16:06:16

4

如果你明確地鍵入它,它會工作,即

Action<paramType1, paramType2> helperAction = (/* parameter names */) => { /* code to encapsulate */ }; 
Func<paramType1, paramType2, returnType> helperFunction = (/* parameter names */) => { /* code to encapsulate */ }; 

var不起作用的原因是lambda表達式可以評估爲多種類型(我相信委託或表達式樹,但不要引用我就此而言),編譯器在這種情況下無法推斷出這是什麼意思。

+0

對於爲什麼var使用lambda表達式失敗,聽起來似乎足夠合理,但編譯器可以輕鬆推斷出較老的delegate(){}語法。 var x = delegate(){return constantexpr};也是一個錯誤。也許這只是一個「對不起,還沒完成......也許在C#6.0人中!」的情況! :-S。 – TerryP 2010-08-01 16:40:13

1

您不能將var關鍵字用於lambda表達式或委託,因爲它們都需要額外的上下文信息(委託需要返回類型,而lambda需要返回類型和參數類型)。例如,(params) => { code }語法要求能夠推斷參數類型和返回類型的工作方式:通過明確地給它一個類型來實現。

通用System.Action委託類型(收益void)可以在做好你想什麼:

Action<ArgumentType1, ArgumentType2, ...> myDelegate = (params) => { code }; 

否則,也就是在System.Func,其中有一個返回類型,必須作爲傳遞最後的一般論證。

2

我建議看Action<T>Func<TResult>代表和他們的過載。你可以做這樣的事情

static void Main(string[] args) 
{ 
    SomeMethod(); 
} 

private static void SomeMethod() 
{ 
    Action<int> action = (num) => Console.WriteLine(num); 

    Enumerable.Range(1,10).ToList().ForEach(action); 

    Console.ReadKey(); 
} 

這裏SomeMethod是私有的,有一個本地Action<int> delgate接受一個int並做一些事情吧。

我認爲你遇到的問題是,當將lambda表達式分配給一個變量時,你不能使用隱式類型(即使用var)。

0

這取決於你的隱藏定義是什麼。

的功能/動作溶液編寫正C#代碼時(如一個斯科特建議)

void DoSomething() 
{ 
    Func<int,int> addOne = (ii) => ii +1; 
    var two = addOne(1); 
} 

Feals像hidding方法定義,但在看IL等效的時

//This is pseudo code but comes close at the important parts 
public class Class1 
    { 
     //The actual type is different from this 
     private static Func<int, int> myMethod = AnonymousFunction; 

     public void f() 
     { 
      myMethod(0); 
     } 

     private static int AnonymousFunction(int i) 
     { 
      return 1; 
     } 
    } 

所以,如果你真的想從一個「隱藏」的方法中獲得方法,你可以通過反射來實現。存儲委託的字段生成的實際名稱在C#bul中是非法的,在CLR上下文中是有效的,但這是唯一的站在使用德爾的方式egate作爲常規代理存儲在一個字段中(也就是說,如果你計算出該名稱:))

相關問題