Home
Options

What is default accessibility modifier for struct Point in my code?

I am trying to determine whether struct Point is public or internal. It could also be private since the intellisense shows Point
as a member of UserQuery class.
And also what is the accessibility modifier of Main method?

Comments

  • Options

    Both private.

    Remove the Extension Method that won't compile and reflect in ILSpy (Alt-Shift-R) to confirm this.

  • Options

    The short answer is that they are both private. So, in your scenario, you must add an internal or public modifier the Point type.

    The long answer is that LINQPad normally wraps your code in a class called UserQuery. (This is analogous to the way that the C# compiler wraps top-level statements in a method and class.)

    This means that types that you write - such as PointExtensions - are nested within UserQuery. This is usually ideal, because PointExtensions can access members of the containing type without you needing to add accessibility modifiers.

    However, C# has a peculiar restriction when it comes to extension methods. That is, that they can't reside in nested types. Obviously LINQPad knows this, and it isn't going tell you that you can't run your code, so it moves static classes that contain extension methods out of UserQuery so that they're not nested and compile. They can still see nested types in UserQuery (thanks to a static using) - but now those members require an internal or public access modifier in order to be accessible.

    Another interesting footnote is that you can force LINQPad to make all type declarations non-nested with the #LINQPad nonest directive. This can be useful in various other edge-cases.

  • Options

    @sgmoore said:
    Both private.

    Remove the Extension Method that won't compile and reflect in ILSpy (Alt-Shift-R) to confirm this.

    The following code made it work. It compiled and even ran successfully.

  • Options
    edited November 2023

    @JoeAlbahari said:
    The short answer is that they are both private. So, in your scenario, you must add an internal or public modifier the Point type.

    The long answer is that LINQPad normally wraps your code in a class called UserQuery. (This is analogous to the way that the C# compiler wraps top-level statements in a method and class.)

    This means that types that you write - such as PointExtensions - are nested within UserQuery. This is usually ideal, because PointExtensions can access members of the containing type without you needing to add accessibility modifiers.

    However, C# has a peculiar restriction when it comes to extension methods. That is, that they can't reside in nested types. Obviously LINQPad knows this, and it isn't going tell you that you can't run your code, so it moves static classes that contain extension methods out of UserQuery so that they're not nested and compile. They can still see nested types in UserQuery (thanks to a static using) - but now those members require an internal or public access modifier in order to be accessible.

    Another interesting footnote is that you can force LINQPad to make all type declarations non-nested with the #LINQPad nonest directive. This can be useful in various other edge-cases.

    Please take a look at the screenshot in the post submitted a few minutes ago.

    It seems that struc Point and static class PointExtensions are private and nested types OR is the struc Point nested but static class PointExtensions is not nested since LINQPad has behind the scenes pulled it out of the UserQuery class when LINQPad ran the code?

    The exact code that worked in LINQPad is as below.

    void Main()
    {
        Point p = new Point();
        Console.WriteLine("X = {0}, Y = {1}", p.X, p.Y);
        p.X = 10;
        p.Y = 20;
        Console.WriteLine("X = {0}, Y = {1}", p.X, p.Y);
        Console.WriteLine("The distance of ({0},{1}) from (0,0) is {2}", p.X,p.Y,  p.GetDistanceFromOrigin());
    }
    
    
    // Define other methods and classes here
    struct Point
    {
      int x;
      int y;
    
      public int X { get; set;}
      public int Y { get; set;}
    }
    
    static class PointExtensions
    {
        public static int GetDistanceFromOrigin(this Point p)
        {
              return (int)Math.Sqrt( Math.Pow(p.X, 2) + Math.Pow(p.Y,2));
    
        }
    }
    
  • Options

    Ah, you must be running LINQPad 5. This is more heavy-handed, and will also extract the Point struct in this scenario (because it's required by your extension method). This is why you've ended up with no nested types.

    The level of auto-magic was stepped down in LINQPad 6/7/8, to make its behavior more easily predictable. In LINQPad 6/7/8, it only unnests types that it absolutely has to (i.e., static classes containing extension methods) - unless you use the #LINQPad nonest directive (in which case it unnests everything).

  • Options

    Also, in LINQPad 7/8, you can disable all auto-magic as follows, if you want to investigate C#'s normal accessibility rules without nested types:

    namespace Test
    {
        class Foo
        {
            static void Main()
            {
                new Point { X = 3}.GetDistanceFromOrigin().Dump();
            }
        }
    
        struct Point
        {
            int x;
            int y;
    
            public int X { get; set; }
            public int Y { get; set; }
        }
    
        static class PointExtensions
        {
            public static int GetDistanceFromOrigin (this Point p)
            {
                return (int)Math.Sqrt (Math.Pow (p.X, 2) + Math.Pow (p.Y, 2));    
            }
        }
    }
    
  • Options
    edited November 2023

    @JoeAlbahari said:
    Ah, you must be running LINQPad 5. This is more heavy-handed, and will also extract the Point struct in this scenario (because it's required by your extension method). This is why you've ended up with no nested types.

    The level of auto-magic was stepped down in LINQPad 6/7/8, to make its behavior more easily predictable. In LINQPad 6/7/8, it only unnests types that it absolutely has to (i.e., static classes containing extension methods) - unless you use the #LINQPad nonest directive (in which case it unnests everything).

    The version of LINQPad I have is 4.59.00

    OK, so that's cool if LINQPad is unnesting the types as per the situation. That means, ultimately these types in my code are becoming internal or public. Is that right?

    I used your sample code in the last post and the namespace part had to be removed since LINQPad complained "Invalid token 'namespace' in class, struct, or interface member declaration", after which it worked.

    Also, when I put the directive #LINQPad nonest at the start of my code, LINQPad complained "Single-line comment or end-of-line expected". However, when I instead put the directive #define NONEST then LINQPad compiled successfully, but I'm not sure if its doing the same job of unnesting the types.

  • Options

    The types accessibility will remain internal (the default). LINQPad does not change the accessibility of any of your types.

    I don't think 4.59 supports the nonest option, nor the ability to define namespaces.

Sign In or Register to comment.