Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. "interface hack" to make private nested class instances available to outer class methods ?

"interface hack" to make private nested class instances available to outer class methods ?

Scheduled Pinned Locked Moved C#
csharplinqquestion
16 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Lost User

    I'd be more impressed if that code actually compiled. But even then I don't really understand what point you are trying to demonstrate.

    B Offline
    B Offline
    BillWoodruff
    wrote on last edited by
    #5

    Thanks, added the missing 'GetSomething method, and verified it compiles/runs as expected.. Re "point:" please see response to Griff; if there is anyone on the planet I think would instantly see the "point," and be aware of the issue ... and blow my mind with a better technique ...I would pick: you :omg:

    «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

    1 Reply Last reply
    0
    • B BillWoodruff

      Hi Griff, I bet my brain-fog right now is thicker than yours :) Of course, you are right that inner nested classes declared 'private are inaccessible in all cases to users of instances of the Outer class. In this case, it is the fact the inner class 'Something1 (declared 'private) inherits from a public interface that allows the 'AddSomething method in the outer class to both update the private list, and return the new 'ISomething1. Any other access declaration on the 'Something1 class would mean it is exposed to users of the outer class. imho, this is part of the weirdness with which nested classes are handled in C#. And, in my head, now, I see using this method is a way ... awkward ! ... to achieve strong encapsulation, as taught by Saint SOLID. I eagerly await enlightenment ! cheers, Bill

      «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #6

      Being pedantic, the class implements the interface; it doen't inherit from it. :) And there's no actual reference to the nested Something1 class anywhere in that code. You could remove that class, and the code would continue to run and function as expected.


      "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      B 1 Reply Last reply
      0
      • B BillWoodruff

        If you are not familiar with this technique, I will publish a Tip/Trick soon. Assuming you know how a nested inner class (which implements an Interface) can be declared 'private, and still be accessed by public methods in the enclosing outer class: which does make direct access to inner classes of the OuterClass prohibited. Do you think the technique shown here is evil, undesirable, or ... ? usage:

        // necessary depending on use
        // using NestedClassExample1;

        OuterClass1 oc1 = new OuterClass1();

        var cat1 = oc1.AddSomething(new Cat("cat1", "meow"));
        var cat2 = oc1.AddSomething(new Cat("cat2", "hiss"));
        var dog1 = oc1.AddSomething(new Dog("dog1"));

        var cat1instance = oc1.GetSomething("cat1");

        class:

        using System;
        using System.Collections.Generic;
        using System.Linq;

        namespace NestedClassExample1
        {
        public interface ISomething1
        {
        string Name { get; }
        }

        public class OuterClass1
        {
            private List Somethings = new List();
        
            internal ISomething1 AddSomething(ISomething1 newsomething)
            {
                Somethings.Add(newsomething);
                return newsomething;
            }
        
            internal ISomething1 GetSomething(string name)
            {
                return Somethings.FirstOrDefault(smtng => smtng.Name == name);
            }
        }
        
        public class Cat : ISomething1
        {
            public Cat(string name, string sound = "")
            {
                Name = name;
                CatSound = sound;
            }
            public string Name { get; }
            public string CatSound { set; get; }
        }
        
        public class Dog : ISomething1
        {
            public Dog(string name, string sound = "")
            {
                Name = name;
                DogSound = sound;
            }
        
            public string Name { get; }
            public string DogSound { set; get; }
        }
        
        public class Tiger : ISomething1
        {
            public Tiger(string name) { Name = name; }
            public string Name { get; }
        }
        

        }

        «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

        L Offline
        L Offline
        Lost User
        wrote on last edited by
        #7

        If the trick is intended to center around being able to return instances of a private class (which otherwise results in the dreaded "inconsistent accessibility" error) in an at least someone useful way (you can always return it as object, but then what?), then that's known .. by me at least, but I guess in general. The code doesn't really show that in action though. I wouldn't rate that an evil trick, more like "limited usefulness". Otherwise if it's supposed to be a different trick then I didn't get it.

        B 2 Replies Last reply
        0
        • Richard DeemingR Richard Deeming

          Being pedantic, the class implements the interface; it doen't inherit from it. :) And there's no actual reference to the nested Something1 class anywhere in that code. You could remove that class, and the code would continue to run and function as expected.


          "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

          B Offline
          B Offline
          BillWoodruff
          wrote on last edited by
          #8

          "pedantic" ? oh, we know what to do with that :omg:

          Richard Deeming wrote:

          And there's no actual reference to the nested Something1 class anywhere in that code.

          That's the point: the consumer of an instance of 'OuterClass has no direct access to the plumbing ... except through those publicly exposed methods.

          Richard Deeming wrote:

          You could remove that class, and the code would continue to run and function as expected.

          Wrong. See Harold's response and my reply below.

          «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

          Richard DeemingR 1 Reply Last reply
          0
          • L Lost User

            If the trick is intended to center around being able to return instances of a private class (which otherwise results in the dreaded "inconsistent accessibility" error) in an at least someone useful way (you can always return it as object, but then what?), then that's known .. by me at least, but I guess in general. The code doesn't really show that in action though. I wouldn't rate that an evil trick, more like "limited usefulness". Otherwise if it's supposed to be a different trick then I didn't get it.

            B Offline
            B Offline
            BillWoodruff
            wrote on last edited by
            #9

            Hi Harold, you got it. Thanks !

            harold aptroot wrote:

            intended to center around being able to return instances of a private class (which otherwise results in the dreaded "inconsistent accessibility" error)

            "Generally known" ? My guess is it is not generally known ... took me quite an effort to locate any discussion of it.

            harold aptroot wrote:

            The code doesn't really show that in action though.

            I would argue it does show that, in the use of the Add/Get-Something methods. "Limited" ? Yes, the example shown here is a bare-bones demo of a technique for encapsulation ... of declared 'private inner classes, and of internal collections of instances of those classes, I asked for opinions about its use because: 1) it's very unusual in my experience 2) it uses Interface in a very different way than usual. 3) it "feels" awkward to me.

            «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

            1 Reply Last reply
            0
            • B BillWoodruff

              "pedantic" ? oh, we know what to do with that :omg:

              Richard Deeming wrote:

              And there's no actual reference to the nested Something1 class anywhere in that code.

              That's the point: the consumer of an instance of 'OuterClass has no direct access to the plumbing ... except through those publicly exposed methods.

              Richard Deeming wrote:

              You could remove that class, and the code would continue to run and function as expected.

              Wrong. See Harold's response and my reply below.

              «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

              Richard DeemingR Offline
              Richard DeemingR Offline
              Richard Deeming
              wrote on last edited by
              #10

              BillWoodruff wrote:

              Wrong.

              Are you sure about that? With the nested class: NestedClassExample1 | C# Online Compiler | .NET Fiddle[^] Without the nested class: [Fork] NestedClassExample1 | C# Online Compiler | .NET Fiddle[^] Both compile and run without errors, and produce identical output. The AddSomething and GetSomething methods depend on the interface, not the unused nested class.


              "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

              "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

              B 1 Reply Last reply
              0
              • Richard DeemingR Richard Deeming

                BillWoodruff wrote:

                Wrong.

                Are you sure about that? With the nested class: NestedClassExample1 | C# Online Compiler | .NET Fiddle[^] Without the nested class: [Fork] NestedClassExample1 | C# Online Compiler | .NET Fiddle[^] Both compile and run without errors, and produce identical output. The AddSomething and GetSomething methods depend on the interface, not the unused nested class.


                "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                B Offline
                B Offline
                BillWoodruff
                wrote on last edited by
                #11

                Richard Deeming wrote:

                The AddSomething and GetSomething methods depend on the interface, not the unused nested class.

                Hi, Thanks for looking further into the code ! You are correct that the class definition for 'ISomething1 is not used in the use-case example (it's a fossil from an earlier version), and I will delete that from the code posted here, thanks ! Sorry for any confusion that added. Those two methods, by design, can only be accessed via an instance of 'OuterClass; while they use the public Interface, I don't see them as "dependent" in the usual sense of that term. My hypothesis here is limited in scope: does this technique contribute to the encapsulation of the collections of Instances in the outer class that implement the Interface. This code example is, by design, a terse example. I also use generics in a way not shown in this example ... imho, does not need to be shown. The "big picture," imho, is: 1) if you are managing collections of mixed Types (which requires use of Interface), where extensibility ... the user can create new Types that use the Interface ... is important ... 2) and, you want maximum encapsulation of those collections 3) what are good techniques ? cheers, Bill

                «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

                Richard DeemingR 1 Reply Last reply
                0
                • B BillWoodruff

                  Richard Deeming wrote:

                  The AddSomething and GetSomething methods depend on the interface, not the unused nested class.

                  Hi, Thanks for looking further into the code ! You are correct that the class definition for 'ISomething1 is not used in the use-case example (it's a fossil from an earlier version), and I will delete that from the code posted here, thanks ! Sorry for any confusion that added. Those two methods, by design, can only be accessed via an instance of 'OuterClass; while they use the public Interface, I don't see them as "dependent" in the usual sense of that term. My hypothesis here is limited in scope: does this technique contribute to the encapsulation of the collections of Instances in the outer class that implement the Interface. This code example is, by design, a terse example. I also use generics in a way not shown in this example ... imho, does not need to be shown. The "big picture," imho, is: 1) if you are managing collections of mixed Types (which requires use of Interface), where extensibility ... the user can create new Types that use the Interface ... is important ... 2) and, you want maximum encapsulation of those collections 3) what are good techniques ? cheers, Bill

                  «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

                  Richard DeemingR Offline
                  Richard DeemingR Offline
                  Richard Deeming
                  wrote on last edited by
                  #12

                  I'm not sure I follow. Are you saying you want to prevent the user from creating new types that implement the interface outside of your assembly?


                  "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                  "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                  B 1 Reply Last reply
                  0
                  • Richard DeemingR Richard Deeming

                    I'm not sure I follow. Are you saying you want to prevent the user from creating new types that implement the interface outside of your assembly?


                    "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                    B Offline
                    B Offline
                    BillWoodruff
                    wrote on last edited by
                    #13

                    Richard Deeming wrote:

                    prevent the user from creating new types that implement the interface outside of your assembly?

                    That is a very logical next step, but this example is limited to only preventing use of the OuterClass' collections, In this example, the end user is free to create as many Dogs and Cats as they can afford :) p.s. the code gets more interesting when you define an encapsulated instantiator like this:

                    // in OuterClass1
                    internal T NewInstance(params object[] args)
                    where T : class, ISomething1
                    {
                    var ttype = typeof(T);

                    ISomething1 instance = null;
                    
                    instance = (T) Activator.CreateInstance(ttype, args);
                    
                    Somethings.Add(instance);
                    
                    return (T) instance;
                    

                    }

                    Which is, of course, only one way to handle instantiation; I tend to avoid 'Activator.CreateInstance for reasons I am sure you are aware of. Returning to the "big picture:" what strategies do you use to increase the encapsulation of classes that maintain collections of mixed types ? cheers, Bill

                    «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

                    Richard DeemingR 1 Reply Last reply
                    0
                    • L Lost User

                      If the trick is intended to center around being able to return instances of a private class (which otherwise results in the dreaded "inconsistent accessibility" error) in an at least someone useful way (you can always return it as object, but then what?), then that's known .. by me at least, but I guess in general. The code doesn't really show that in action though. I wouldn't rate that an evil trick, more like "limited usefulness". Otherwise if it's supposed to be a different trick then I didn't get it.

                      B Offline
                      B Offline
                      BillWoodruff
                      wrote on last edited by
                      #14

                      @Harold the code gets more interesting when you define an encapsulated instantiator like this:

                      // in OuterClass1
                      internal T NewInstance(params object[] args)
                      where T : class, ISomething1
                      {
                      var ttype = typeof(T);

                      ISomething1 instance = null;
                      
                      instance = (T) Activator.CreateInstance(ttype, args);
                      
                      Somethings.Add(instance);
                      
                      return (T) instance;
                      

                      }

                      Which is, of course, only one way to handle instantiation; I tend to avoid 'Activator.CreateInstance for reasons I am sure you are aware of. Returning to the "big picture:" what strategies do you use to increase the encapsulation of classes that maintain collections of mixed types ? cheers, Bill

                      «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

                      1 Reply Last reply
                      0
                      • B BillWoodruff

                        Richard Deeming wrote:

                        prevent the user from creating new types that implement the interface outside of your assembly?

                        That is a very logical next step, but this example is limited to only preventing use of the OuterClass' collections, In this example, the end user is free to create as many Dogs and Cats as they can afford :) p.s. the code gets more interesting when you define an encapsulated instantiator like this:

                        // in OuterClass1
                        internal T NewInstance(params object[] args)
                        where T : class, ISomething1
                        {
                        var ttype = typeof(T);

                        ISomething1 instance = null;
                        
                        instance = (T) Activator.CreateInstance(ttype, args);
                        
                        Somethings.Add(instance);
                        
                        return (T) instance;
                        

                        }

                        Which is, of course, only one way to handle instantiation; I tend to avoid 'Activator.CreateInstance for reasons I am sure you are aware of. Returning to the "big picture:" what strategies do you use to increase the encapsulation of classes that maintain collections of mixed types ? cheers, Bill

                        «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

                        Richard DeemingR Offline
                        Richard DeemingR Offline
                        Richard Deeming
                        wrote on last edited by
                        #15

                        I'm still not entire sure what you're trying to achieve. If a generic collection contains mixed types, those types must either inherit from a base class, or implement an interface. If the collection class is public, then trying to further restrict the types it can contain to those in the current assembly, or an approved list of assemblies, is usually a sign of a broken design.


                        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                        "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                        B 1 Reply Last reply
                        0
                        • Richard DeemingR Richard Deeming

                          I'm still not entire sure what you're trying to achieve. If a generic collection contains mixed types, those types must either inherit from a base class, or implement an interface. If the collection class is public, then trying to further restrict the types it can contain to those in the current assembly, or an approved list of assemblies, is usually a sign of a broken design.


                          "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                          B Offline
                          B Offline
                          BillWoodruff
                          wrote on last edited by
                          #16

                          Thanks !

                          Richard Deeming wrote:

                          If the collection class is public, then trying to further restrict the type ...

                          In this case, the 'OuterClass is public; the whole point of this (encapsulation) is allowing access to the internal collections inside that outer class only by methods I expose. I think you are reading into this some broader issue.

                          Richard Deeming wrote:

                          ... to those in the current assembly, or an approved list of assemblies, is usually a sign of a broken design.

                          I can easily imagine a scenario where a design of an outer class with private internal classes would be very useful. But, that is not relevant here. cheers, Bill

                          «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups