14

我会发现为嵌套类中的类编写我的扩展很方便/合乎逻辑。主要原因是我可以简单地命名该类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);
      }
   }
}

而现在我必须创建一个单独的独立课程。

更新/注意:我没想到它是一个内部类的事实会影响扩展方法的可用性范围。我只想用一个单独的名称来解决实际的编码问题。

4

3 回答 3

8

这里的关键点是嵌套类可以访问外部类中的私有字段。

所以下面的代码有效:

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();

根据评论进行编辑

为什么扩展方法等同于实例方法是个坏主意?

Eric Lippert 的话(强调我的):

所以,是的,经常听到的批评“扩展方法不是面向对象的”是完全正确的,但也相当不相关。扩展方法当然不是面向对象的。他们将处理数据的代码远离声明数据的代码,他们无法打破封装并与他们似乎是方法的对象的私有状态对话,他们不能很好地处理继承,等等。他们穿着方便的面向对象的衣服进行过程编程。

于 2012-08-20T12:39:57.277 回答
2

没有技术原因 - 只是实用。如果您的扩展方法的范围仅限于单个类,只需将其定义为您的类中的常规静态方法并删除“this”。扩展用于在多个类之间共享。

于 2012-07-12T01:25:36.813 回答
1

我猜想不允许这件事背后的想法是因为扩展方法适用于命名空间中的所有实体。

如果您将创建一个嵌套的扩展方法类,那么它将仅适用于嵌套它的类。在这种情况下,创建扩展方法没有意义。然后任何正常的非扩展方法都可以。

于 2012-07-12T01:24:32.333 回答