15

I would find it convenient/logical to write my exensions for a class in a nested class. The main reason is I could simply name that class Extensions and let it's outer naming scope give it a unique type name for the compiler.

What is the technical reason to disallow something like:

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

Whereas now I have to create a separate free standing class.

Update/Note: I wasn't imagining that the fact it was an inner class would affect the scope of availability of the extension method. I only wanted to address the practical coding issue a separate class with a separate name.

Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121
  • Likely #4: High cost for the compiler to analyze. http://blogs.msdn.com/b/ericlippert/archive/2012/06/18/implementation-defined-behaviour.aspx – Darren Kopp Jul 12 '12 at 01:25
  • Duplicate: http://stackoverflow.com/a/3934737/1464699 – Kevin Aenmey Jul 12 '12 at 01:30
  • possible duplicate of [Why are extension methods only allowed in non-nested, non-generic static class?](http://stackoverflow.com/questions/3930335/why-are-extension-methods-only-allowed-in-non-nested-non-generic-static-class) – Reed Copsey Jul 12 '12 at 01:30
  • oops. i should be better about researching for duplicates... – Aaron Anodide Jul 12 '12 at 01:31
  • @ReedCopsey, looking at the answer to the question you referenced, I'd say I've provided a real world example of why they might be allowed, no? – Aaron Anodide Jul 12 '12 at 01:37
  • @AaronAnodide In the example provided, I'd just make it a method on Foo - I don't see a *compelling* reason from just this code... – Reed Copsey Jul 12 '12 at 16:04
  • @ReedCopsey, I'm missing something - my defined extension method accepts `this ObjectSet` and is only related to Foo insofar as Foo is its parent naming container (this is what my intention was - but I'm starting to think I don't understand something at another level) – Aaron Anodide Jul 12 '12 at 18:48
  • @ReedCopsey, OK now I think I get it, you'd make it a method on Foo that accepted the ObjectSet as an input, right? – Aaron Anodide Jul 12 '12 at 19:04
  • @AaronAnodide Yeah - and if it's really intended to be used on Foo, it could just be an instance method without the parameter.. – Reed Copsey Jul 12 '12 at 19:09
  • @ReedCopsey, I'll look at EF again and see if that's possible - if it is you'll have helped me alot! – Aaron Anodide Jul 12 '12 at 20:13
  • @AaronAnodide You should be able to add your methods via partial classes – Reed Copsey Jul 12 '12 at 20:56
  • Possible duplicate of [Why are extension methods only allowed in non-nested, non-generic static class?](https://stackoverflow.com/questions/3930335/why-are-extension-methods-only-allowed-in-non-nested-non-generic-static-class) – TylerH Jan 08 '19 at 22:34

3 Answers3

8

The key point here is that nested classes can access private fields in the outer class.

So the following code works:

public class Foo
{
    private bool _field;

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

Here you are explicitly passing in an instance of the class, and a static method is allowed to access a private field... seems reasonable:

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

However, although extension methods are just an alternative syntax for static methods, they are invoked the same way as non-static instance methods.

Now if extension methods were allowed in nested classes, they could in fact access private fields, and they would be that much closer to instance methods. This could lead to some unintended consequences.

In summary, if this were allowed:

public class Foo
{
    private bool _field;

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

Then you could write the following code, making the extension method behave a bit more like an instance method than it should be:

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

Edit as a result of comments

Why is it a bad idea for extension methods to be equivalent to instance methods?

In Eric Lippert's words (emphasis mine):

So, yes, the oft-heard criticism that "extension methods are not object-oriented" is entirely correct, but also rather irrelevant. Extension methods certainly are not object-oriented. They put the code that manipulates the data far away from the code that declares the data, they cannot break encapsulation and talk to the private state of the objects they appear to be methods on, they do not play well with inheritance, and so on. They're procedural programming in a convenient object-oriented dress.

Zaid Masud
  • 13,225
  • 9
  • 67
  • 88
  • 3
    What's the problem in your latter example? If `GetField` had been an ordinary method declared within `Foo`, it would certainly be expected to have access to `_field`. Likewise, if one were to call `Foo.Extensions.GetField(foo)` one would expect that to have access to `_field` as well. So why shouldn't the extension method? To be sure, if I were designing the language, extension methods in a nested class would only be available in the immediate surrounding class, but such restriction would enhance the usefulness of extension methods as a feature. – supercat Dec 06 '13 at 21:54
  • @supercat using the [information hiding (encapsulation)](http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)) principle, extension methods should behave, as much as possible, like static methods declared outside the class. They shouldn't have access to private fields. – Zaid Masud Dec 07 '13 at 18:49
  • 4
    The code *within a class* gets to decide how state contained in the class's private fields is exposed to the outside world. If one doesn't want certain state exposed, don't include static methods that expose it. Note that if the extension method above had used a `Bar` as its `this` parameter, it would only have access to the variables and types associated with `Foo`, rather than those of `Bar`. Besides, the biggest reason I would have liked to allow extension methods to be declared in nested classes would have been to allow their scope to be limited to the outer class (e.g. ... – supercat Dec 07 '13 at 19:55
  • 1
    ...if the class which immediately contains the extension method were private, protected, or internal, then use of the method would be restricted to code which could see that class, and the extension method could accept parameters of types which were also only visible within that outer class. For cases where an extension method is supposed to be public, proper visibility can be achieved by having a class that wants its internals to be made visible via that extension method define a public or internal static method and having the extension method chain to that. – supercat Dec 07 '13 at 19:59
  • Such an approach is often necessary and appropriate in cases where an extension method which is supposed to have broad visibility has to operate on a generic type (e.g. if one uses `void DoSomething(this Foo it) where T:class {FooHelper.DoSomething(it);}`, then `FooHelper` could contain a `ConditionalWeakTable`, but if the method is really only intended for use within class `Woozle`, it would be cleaner if it could simply use a non-generic call within the class instead of making a generic call which would then have to do a generic class lookup. – supercat Dec 07 '13 at 20:05
  • @supercat I see what you're saying and agree with you to some extent. But I think if you really wanted to declare a restricted visibility *extension* method within a class itself (or a nested class) could you not accomplish that better with a private non-static instance method? – Zaid Masud Dec 07 '13 at 20:42
  • Only when one *has* an instance of the class in question. Sometimes it may be useful to have an extension method which e.g. operates on an instance of an outside class to yield an instance of a class to which one has access. Because generic method calls require that one specify either all or none of the parameters, but extension methods can infer the type of `this` when all other types are specified, extension-method syntax `MyEnumerable.ToSequence()` can be much cleaner than `MakeSequence,T>(MyEnumerable)`. – supercat Dec 07 '13 at 21:10
  • @supercat yeah I suppose so. Although extension methods also require an instance of the class in question :) To be honest I haven't come across the specific case you're describing so I'm having a hard time relating to it. I'll need to think about it some more! – Zaid Masud Dec 08 '13 at 01:54
  • 2
    In my example, using the extension method on `IEnumerable` would require having an instance of *something that implements IEnumerable*, but not necessarily an instance *of the class which wants to use the extension method*. – supercat Dec 08 '13 at 02:09
  • @ZaidMasud "...extension methods should behave, as much as possible, like static methods declared outside the class." I disagree completely. If I wanted a static method declared outside of the class, I would just write one. The primary reason I use extension methods is to add functionality to a class I can't change as though those methods had come with the class. The only major exception to this is cleaner null handling, since extension methods can be called on a null instance. – Sean Worle Jan 04 '19 at 21:50
  • @SeanWorle interesting perspective, but note that my comment is in the context of information hiding only, not on extensibility as you suggest. I did want to add, when you say "add functionality to a class I can't change as though those methods had come with the class," note that the extension method is acting on an instance of the class, and does not have all the privileges (e.g. private variables) that an instance method has. Per Open Close Principle (OCP), a class should always be open for OO extension. If it is not, then that's not a great design. – Zaid Masud Jan 04 '19 at 22:25
  • @ZaidMasud Yes, you are correct that I could accomplish what I need via OO extension, but the kinds of things I usually need to do are against things like "string", "List", and "DateTime". I don't really want to subclass one of these and then have to use my own custom string class all over the place (for example). – Sean Worle Jan 06 '19 at 22:00
  • @SeanWorle for Framework types, especially value types, it's important to realize that the extension method is syntactic sugar on a static method. It's a more fluent way to invoke the method, but provides you no additional OO benefits. Check out [Eric Lippert's blog](https://blogs.msdn.microsoft.com/ericlippert/2008/10/28/the-future-of-c-part-two/) where he states that extension methods are "procedural programming in a convenient object-oriented dress." – Zaid Masud Jan 07 '19 at 16:09
  • @ZaidMasud Right - I understand the implementation of extension methods, that they are syntactic sugar on static methods. I get that. And I like it, it's useful. I just think it would be MORE useful if the above scenario were supported. You say in your answer "...if extension methods were allowed in nested classes, they could in fact access private fields, and they would be that much closer to instance methods." I say "Yes, that would be really useful behavior. The way I use extension methods, I wish they could be as much like instance methods as possible." – Sean Worle Jan 08 '19 at 19:03
  • @SeanWorle see my edit in the original answer. – Zaid Masud Jan 08 '19 at 20:00
  • When outer class is static then this class can't have private instance fields.Only static private fields. But I still can not use extension method in nested class (( – Denis535 Sep 22 '19 at 10:32
2

There is no technical reason for it - just practical. If you have an extension method that is limited in scope to a single class, just define it as a regular static method in your class and remove the 'this'. Extensions are for sharing across several classes.

Nick Wallace
  • 97
  • 1
  • 2
  • 3
    My guess would be there is a technical reason for it. He's not creating extension methods to extend the containing class, but rather to extend things related to the containing class. I agree it'd be nice to be able to do this. – Matt Greer Jul 12 '12 at 01:29
  • Can I really do that with my example? The extension method's target type is `ObjectSet` - I don't know how to add a static method to that. OK, I think I understand now upon re-reading - you would have me define a static method that takes ObjectSet as the first parameter... fair enough but then I lose the syntactic grace of writing `myContext.Bars.ByName(...)` I would have to write Foo.BarByName(myContext, ...) and that's not horrible, I'll grant you. – Aaron Anodide Jul 12 '12 at 01:30
1

I guess the idea behind disallowing this thing is because Extension Methods are applied for all entities across the namespace.

If you will create a nested Extension Methods class then it will be applicable only to class where it is nested. In that case its not point creating an extension method. Then any normal non-extension method would do.

Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
  • 1
    Any normal non-extension method would *always* do. Why hinder the ability to control the scope of the extension method? – snarf May 27 '19 at 17:51