2012-07-12 75 views
4

我會發現爲嵌套類中的類編寫我的exensions方便/合乎邏輯。主要原因是我可以簡單地命名該類Extensions,並讓它的外部命名範圍爲編譯器提供一個唯一的類型名稱。爲什麼不允許嵌套類中的擴展方法定義?

什麼是技術上的原因不允許這樣的:

public class Foo 
{ 
    ObjectSet<Bar> Bars { get; set; } 

    public static class Extensions 
    { 
     public static Bar ByName(this ObjectSet<Bar> bars, string name) 
     { 
     return bars.FirstOrDefault(c => c.Name == name); 
     } 
    } 
} 

而現在我要創建一個單獨的獨立類。

更新/說明:我並沒有想象它是一個內部類的事實會影響擴展方法的可用性範圍。我只想用一個單獨的名稱來解決實際的編碼問題。

+0

可能#4:編譯器分析成本高。 http://blogs.msdn.com/b/ericlippert/archive/2012/06/18/implementation-defined-behaviour.aspx – 2012-07-12 01:25:48

+0

Duplicate:http://stackoverflow.com/a/3934737/1464699 – 2012-07-12 01:30:07

+0

可能的重複[爲什麼擴展方法只允許在非嵌套的非泛型靜態類中使用?](http://stackoverflow.com/questions/3930335/why-are-extension-methods-only-allowed-in-non-nested-non-generic-static-class) – 2012-07-12 01:30:42

回答

1

我想這背後的想法是因爲擴展方法適用於命名空間中的所有實體。

如果您要創建一個嵌套的擴展方法類,那麼它將只適用於它嵌套的類。在這種情況下,它不是創建擴展方法的要點。那麼任何正常的非擴展方法都可以。

2

它沒有技術上的原因 - 只是實用。如果你有一個擴展方法在範圍上受限於單個類,只需在你的類中定義一個常規的靜態方法並刪除'this'即可。擴展程序用於跨幾個類共享。

+0

我的猜測會是有技術上的原因。他不是創建擴展方法來擴展包含類,而是擴展與包含類有關的東西。我同意能夠做到這一點很好。 – 2012-07-12 01:29:12

+0

我真的可以用我的例子嗎?擴展方法的目標類型是'ObjectSet ' - 我不知道如何爲其添加靜態方法。好吧,我認爲我現在明白重讀 - 你應該定義一個靜態方法,它將ObjectSet 作爲第一個參數......足夠公平,但是然後我失去了編寫myContext.Bars.ByName(。)的語法優雅。 ..)'我必須寫Foo.BarByName(myContext,...),這並不可怕,我會給你。 – 2012-07-12 01:30:33

4

這裏的關鍵是嵌套類可以訪問外部類中的專用字段

所以下面的代碼工作:

public class Foo 
{ 
    private bool _field; 

    public static class Extensions 
    { 
     public static bool GetField(Foo foo) 
     { 
      return foo._field; 
     } 
    } 
} 

這裏你明確地傳遞的類的實例,而靜態方法是允許訪問私有字段...似乎是合理的:

bool fieldValue = Foo.Extensions.GetField(new Foo()); 

但是,雖然擴展方法只是靜態方法的替代語法,但它們的調用方式與非靜態實例方法相同。

現在如果在嵌套類中允許擴展方法,它們實際上可以訪問私有字段,並且它們會更接近實例方法。這可能會導致一些意想不到的後果。

總之,如果這被允許:

public class Foo 
{ 
    private bool _field; 

    public static class Extensions 
    { 
     public static bool GetField(*this* Foo foo) // not allowed, compile error. 
     { 
      return foo._field; 
     } 
    } 
} 

然後,你可以寫下面的代碼,使擴展方法表現得有點更像是一個實例方法比它應該是:

var foo = new Foo(); 
var iGotAPrivateField = foo.GetField(); 
+0

你後面的例子有什麼問題?如果'GetField'是'Foo'中聲明的普通方法,那麼肯定會有'_field'的訪問權限。同樣,如果有人調用'Foo.Extensions.GetField(foo)',人們也期望能夠訪問'_field'。那麼爲什麼不應該擴展方法呢?可以肯定的是,如果我在設計語言,嵌套類中的擴展方法只能在最近的類中使用,但這種限制會增強擴展方法作爲一種功能的用處。 – supercat 2013-12-06 21:54:22

+0

@supercat使用[信息隱藏(封裝)](http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming))原則,擴展方法應儘可能地表現出類似靜態方法類。他們不應該訪問私人領域。 – 2013-12-07 18:49:44

+0

類*中的代碼*可以決定班級私人領域中的狀態如何暴露給外部世界。如果不想暴露某些狀態,請不要包含公開它的靜態方法。請注意,如果上面的擴展方法使用'Bar'作爲其''this'參數,它將只能訪問與'Foo'相關的變量和類型,而不是'Bar'的變量和類型。此外,我希望允許在嵌套類中聲明擴展方法的最大原因是允許它們的作用域限於外部類(例如... – supercat 2013-12-07 19:55:05

相關問題