2012-07-12 39 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

相关问题