Using Reflection With Nested Classes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Robert W.

    #1

    Using Reflection With Nested Classes

    I've almost completed building a Model-View-Controller but have run into a
    snag. When an event is fired on a form control I want to automatically
    updated the "connnected " property in the Model. This works fine if all of
    the properties are at the top (root level) of the model but I'd like to keep
    them in nested classes to organize them better.

    So, for example, part of my data model looks like this (simplified) :

    public class MainClass

    public class NestedClass1

    public bool Property1

    public string Property2

    public class NestedClass2


    .... and so on.



    Outside of the model I instantiate an object of MainClass and then inside
    the contstructor of MainClass I instantiate an object of NestedClass. So,
    for example, 'ObjectMain' would be an instance of MainClass and
    'ObjectNested1' would be an instance of NestedClass1. That all seems to work
    fine.

    I'm now trying to build a method to retrieve the current value of a given
    property. I pass to this method the instance of the model and the name of
    the property. It first looks in the root of MainClass to see if the property
    is there. If it isn't then it starts cycling through the various nested
    classes to see if it's in one of them. Once it finds the correct nested
    class then it retrieves the value of the property.

    But here's the dilemma: I can explicitly specify the name of the nested
    class to retrieve the property value, such as:

    property.GetVal ue(ObjectMain.O bjectNested1, null)

    That works great! But I'd much prefer to keep things more generic so that
    this method would be completely resuable in the future. Yet I cannot figure
    out how to use Reflection (or something else) to get the equivalent of
    'ObjectMain.Obj ectNested1'

    I realize this is a complicated issue but I hope I've explained it
    succinctly and hope even more that someone has a solution!

    Robert Werner
    Vancouver, BC
  • Dave

    #2
    Re: Using Reflection With Nested Classes

    public static void Main()
    {
    Type type = typeof(System.E nvironment);

    foreach (Type nested in type.GetNestedT ypes())
    Console.WriteLi ne(nested.FullN ame);

    // Outputs the following:
    /*
    System.Environm ent+SpecialFold er
    Press any key to continue
    */
    }

    --
    Dave Sexton
    dave@www..jwaon line..com
    -----------------------------------------------------------------------
    "Robert W." <RobertW@discus sions.microsoft .com> wrote in message news:1B781169-5329-402F-AE0B-5B2126D825E5@mi crosoft.com...[color=blue]
    > I've almost completed building a Model-View-Controller but have run into a
    > snag. When an event is fired on a form control I want to automatically
    > updated the "connnected " property in the Model. This works fine if all of
    > the properties are at the top (root level) of the model but I'd like to keep
    > them in nested classes to organize them better.
    >
    > So, for example, part of my data model looks like this (simplified) :
    >
    > public class MainClass
    >
    > public class NestedClass1
    >
    > public bool Property1
    >
    > public string Property2
    >
    > public class NestedClass2
    >
    >
    > ... and so on.
    >
    >
    >
    > Outside of the model I instantiate an object of MainClass and then inside
    > the contstructor of MainClass I instantiate an object of NestedClass. So,
    > for example, 'ObjectMain' would be an instance of MainClass and
    > 'ObjectNested1' would be an instance of NestedClass1. That all seems to work
    > fine.
    >
    > I'm now trying to build a method to retrieve the current value of a given
    > property. I pass to this method the instance of the model and the name of
    > the property. It first looks in the root of MainClass to see if the property
    > is there. If it isn't then it starts cycling through the various nested
    > classes to see if it's in one of them. Once it finds the correct nested
    > class then it retrieves the value of the property.
    >
    > But here's the dilemma: I can explicitly specify the name of the nested
    > class to retrieve the property value, such as:
    >
    > property.GetVal ue(ObjectMain.O bjectNested1, null)
    >
    > That works great! But I'd much prefer to keep things more generic so that
    > this method would be completely resuable in the future. Yet I cannot figure
    > out how to use Reflection (or something else) to get the equivalent of
    > 'ObjectMain.Obj ectNested1'
    >
    > I realize this is a complicated issue but I hope I've explained it
    > succinctly and hope even more that someone has a solution!
    >
    > Robert Werner
    > Vancouver, BC[/color]


    Comment

    • Dave

      #3
      Re: Using Reflection With Nested Classes

      I re-read your post and feel that I didn't answer your question with my initial response. Here is what I believe you were looking
      for:

      using System;

      namespace TestConsole
      {
      public sealed class Startup
      {
      private Startup() {}

      public static void Main()
      {
      ContainerClass obj = new ContainerClass( );

      foreach (System.Reflect ion.PropertyInf o objProp in obj.GetType().G etProperties())
      {
      if (objProp.CanRea d)
      {
      object[] indexer = new object[0];
      object nestedObj = objProp.GetValu e(obj, indexer);

      foreach (System.Reflect ion.PropertyInf o nestedProp in nestedObj.GetTy pe().GetPropert ies())
      {
      if (nestedProp.Can Read)
      {
      Console.WriteLi ne("{0}.{1}={2} ",
      nestedProp.Decl aringType.FullN ame, nestedProp.Name ,
      nestedProp.GetV alue(nestedObj, indexer));
      }
      }
      }
      }

      // Outputs the following:
      /*
      TestConsole.Con tainerClass+Nes tedClass.Proper ty=Hello World
      Press any key to continue
      */
      }
      }

      public class ContainerClass
      {
      public NestedClass NestedInstance { get { return instance; } }

      private NestedClass instance = new NestedClass();

      public class NestedClass
      {
      public string Property { get { return "Hello World"; } }
      }
      }
      }

      --
      Dave Sexton
      dave@www..jwaon line..com
      -----------------------------------------------------------------------
      "Robert W." <RobertW@discus sions.microsoft .com> wrote in message news:1B781169-5329-402F-AE0B-5B2126D825E5@mi crosoft.com...[color=blue]
      > I've almost completed building a Model-View-Controller but have run into a
      > snag. When an event is fired on a form control I want to automatically
      > updated the "connnected " property in the Model. This works fine if all of
      > the properties are at the top (root level) of the model but I'd like to keep
      > them in nested classes to organize them better.
      >
      > So, for example, part of my data model looks like this (simplified) :
      >
      > public class MainClass
      >
      > public class NestedClass1
      >
      > public bool Property1
      >
      > public string Property2
      >
      > public class NestedClass2
      >
      >
      > ... and so on.
      >
      >
      >
      > Outside of the model I instantiate an object of MainClass and then inside
      > the contstructor of MainClass I instantiate an object of NestedClass. So,
      > for example, 'ObjectMain' would be an instance of MainClass and
      > 'ObjectNested1' would be an instance of NestedClass1. That all seems to work
      > fine.
      >
      > I'm now trying to build a method to retrieve the current value of a given
      > property. I pass to this method the instance of the model and the name of
      > the property. It first looks in the root of MainClass to see if the property
      > is there. If it isn't then it starts cycling through the various nested
      > classes to see if it's in one of them. Once it finds the correct nested
      > class then it retrieves the value of the property.
      >
      > But here's the dilemma: I can explicitly specify the name of the nested
      > class to retrieve the property value, such as:
      >
      > property.GetVal ue(ObjectMain.O bjectNested1, null)
      >
      > That works great! But I'd much prefer to keep things more generic so that
      > this method would be completely resuable in the future. Yet I cannot figure
      > out how to use Reflection (or something else) to get the equivalent of
      > 'ObjectMain.Obj ectNested1'
      >
      > I realize this is a complicated issue but I hope I've explained it
      > succinctly and hope even more that someone has a solution!
      >
      > Robert Werner
      > Vancouver, BC[/color]


      Comment

      • Robert W.

        #4
        Re: Using Reflection With Nested Classes

        Dave,

        Perhaps there's an obvious assumption (ie. next step) you've made that I'm
        not aware of but how does this solve my problem? What I need to do is find a
        way in code to find the equivalent of: ObjectMain.Obje ctNested1

        Robert



        "Dave" wrote:
        [color=blue]
        > public static void Main()
        > {
        > Type type = typeof(System.E nvironment);
        >
        > foreach (Type nested in type.GetNestedT ypes())
        > Console.WriteLi ne(nested.FullN ame);
        >
        > // Outputs the following:
        > /*
        > System.Environm ent+SpecialFold er
        > Press any key to continue
        > */
        > }
        >
        > --
        > Dave Sexton
        > dave@www..jwaon line..com[/color]

        Comment

        • Dave

          #5
          Re: Using Reflection With Nested Classes

          My second post illustrates how you can dynamically access the values' of properties, of a property, of a given object. It does not
          matter where the object reference of a property is declared:

          "Object1" has property, "Property1" of type "Object2". Object2 can be nested, or not. It doesn't matter.

          To get the value of a property of Object2, you need first an instance of Object1 that has Property1 set to an instance of Object2.
          From here, you can enumerate the properties of Object2.

          I'm not sure why you're having trouble with the fact that Property1 is of a type that is nested. It shouldn't matter if you have a
          reference to Object1.


          --
          Dave Sexton
          dave@www..jwaon line..com
          -----------------------------------------------------------------------
          "Robert W." <RobertW@discus sions.microsoft .com> wrote in message news:B045E751-3906-435D-841F-033C45BA09E7@mi crosoft.com...[color=blue]
          > Dave,
          >
          > Perhaps there's an obvious assumption (ie. next step) you've made that I'm
          > not aware of but how does this solve my problem? What I need to do is find a
          > way in code to find the equivalent of: ObjectMain.Obje ctNested1
          >
          > Robert
          >
          >
          >
          > "Dave" wrote:
          >[color=green]
          >> public static void Main()
          >> {
          >> Type type = typeof(System.E nvironment);
          >>
          >> foreach (Type nested in type.GetNestedT ypes())
          >> Console.WriteLi ne(nested.FullN ame);
          >>
          >> // Outputs the following:
          >> /*
          >> System.Environm ent+SpecialFold er
          >> Press any key to continue
          >> */
          >> }
          >>
          >> --
          >> Dave Sexton
          >> dave@www..jwaon line..com[/color]
          >[/color]


          Comment

          • Robert W.

            #6
            Re: Using Reflection With Nested Classes

            Dave,

            Above & beyond the call. Thank you so much!!!

            Being new to C# I need to thoroughly study your code more but I think my
            problem lies in that my "connection " between the ContainerObject and the
            NestedObject is much more limited than the way you did it.

            For all I did was the equivalent of this:

            public NestedClass NestedObject = new NestedClass();


            But I'm not beginning to think that my approach really doesn't provide any
            actual connection between the two classes. Your way does and I think
            provides me a solid path to my solution.

            Got to get some sleep now but will revisit tomorrow and respost here when I
            know more.

            Thank you again!

            Robert W.




            "Dave" wrote:
            [color=blue]
            > I re-read your post and feel that I didn't answer your question with my initial response. Here is what I believe you were looking
            > for:
            >
            > using System;
            >
            > namespace TestConsole
            > {
            > public sealed class Startup
            > {
            > private Startup() {}
            >
            > public static void Main()
            > {
            > ContainerClass obj = new ContainerClass( );
            >
            > foreach (System.Reflect ion.PropertyInf o objProp in obj.GetType().G etProperties())
            > {
            > if (objProp.CanRea d)
            > {
            > object[] indexer = new object[0];
            > object nestedObj = objProp.GetValu e(obj, indexer);
            >
            > foreach (System.Reflect ion.PropertyInf o nestedProp in nestedObj.GetTy pe().GetPropert ies())
            > {
            > if (nestedProp.Can Read)
            > {
            > Console.WriteLi ne("{0}.{1}={2} ",
            > nestedProp.Decl aringType.FullN ame, nestedProp.Name ,
            > nestedProp.GetV alue(nestedObj, indexer));
            > }
            > }
            > }
            > }
            >
            > // Outputs the following:
            > /*
            > TestConsole.Con tainerClass+Nes tedClass.Proper ty=Hello World
            > Press any key to continue
            > */
            > }
            > }
            >
            > public class ContainerClass
            > {
            > public NestedClass NestedInstance { get { return instance; } }
            >
            > private NestedClass instance = new NestedClass();
            >
            > public class NestedClass
            > {
            > public string Property { get { return "Hello World"; } }
            > }
            > }
            > }
            >
            > --
            > Dave Sexton
            > dave@www..jwaon line..com[/color]

            Comment

            • Robert W.

              #7
              Re: Using Reflection With Nested Classes

              Hi Dave,

              I was sick today and got absolutely nothing done work-wise. I meant to ask
              you one other thing related to all this:

              When I first learned about nested classes I just assumed that an inner class
              was essentially the child of the outer class. What I mean is that once
              defined and once the inner class is instantiated (in the simple way that I
              did it) in the outer class's constructor, that a parent-child relationship is
              set up.

              This belief seemed to be reenforced when I learned how to use the FieldInfo
              of Reflection to gather the structure of the class definition. So naturally,
              I thought, if there's a relationship with the class definition then there'd
              "obviously" be a relationship with the object created from these classes.

              But after seeing your code (which I still do have to test thoroughly and
              implement myself) I began to wonder if the whole nested classes concept was
              more a matter of simple visual convenience than anything else.

              For example, let's look at two scenarios:

              Configuration 1:

              class OuterClass
              {
              OuterClass() // constructor
              {
              InnerClass innerObject = new InnerClass();
              }

              class InnerClass
              {
              }
              }



              Configuration 1:

              class OuterClass
              {
              OuterClass() // constructor
              {
              InnerClass innerObject = new InnerClass();
              }
              }


              class InnerClass // Could even be in a separate file
              {
              }



              After reviewing (and thinking about) your code I began to wonder if all of
              my earlier assumptions were incorrect. In fact, in terms of an actual
              parent-child relationship between the OuterObject and the InnerObject:
              - There really is none, if configured as above, is there?
              - There's really no difference between the two configurations above, is
              there?

              I apologize if all of these seem like dumb (read "obvious") questions but
              the articles and other explanations I've found on nested classes aren't very
              comprehensive.

              Robert W.





              "Robert W." wrote:
              [color=blue]
              > Dave,
              >
              > Above & beyond the call. Thank you so much!!!
              >
              > Being new to C# I need to thoroughly study your code more but I think my
              > problem lies in that my "connection " between the ContainerObject and the
              > NestedObject is much more limited than the way you did it.
              >
              > For all I did was the equivalent of this:
              >
              > public NestedClass NestedObject = new NestedClass();
              >
              >
              > But I'm not beginning to think that my approach really doesn't provide any
              > actual connection between the two classes. Your way does and I think
              > provides me a solid path to my solution.
              >
              > Got to get some sleep now but will revisit tomorrow and respost here when I
              > know more.
              >
              > Thank you again!
              >
              > Robert W.[/color]

              Comment

              • Dave

                #8
                Re: Using Reflection With Nested Classes

                You are right that there is no instance-relationship between nested classes. If you instanciate a class that contains a nested
                class, the nested class isn't automattically instanciated.

                Think of classes as templates, and objects as a runtime instance of a template. If a template contains another template, then
                that's just the location of the defination of the template as you explained in your post.

                It is not recommended that you make classes nested except in cases where your nested classes will be private. This is useful for
                when you need to hide a class implementation that will be consumed only by the containing "template". If you have to make a nested
                class public, then it probably shouldn't be a nested class. If you notice in VS.NET intellisense/object browser there is little
                support for nested classes. This is probably because it is assumed that nested classes are for private implementations only, even
                though they can be made as public.

                The code I gave you illustrates the relationship between a nested class and and object instance at runtime, i.e. there is none, or
                it's no different than any other class relationship.

                Reflection lets you look at the metadata for a class, i.e. it's members but not it's implementation. Therefore, in your code
                examples, you must have a member of the same Type as the nested class in order for you to reflect in the object and gain information
                about the nested class instance. (Like I commented in my code example, whether a member is of a nested class or not, Reflection
                will be the same code.)

                Check out my comments:
                [color=blue]
                > class OuterClass
                > {[/color]
                // Now when you enumerate the fields of an instance of OuterClass
                // you will find this field, which just so happens to be of a Type
                // that is nested. Using an instance of OuterClass, you can obtain an
                // instance of InnerClass through this field (if it is not set to null).
                InnerClass innerObject = new InnerClass();
                [color=blue]
                > OuterClass() // constructor
                > {[/color]
                // You won't be able to reflect this instance because it is confined to
                // the implementation of the constructor.[color=blue]
                > InnerClass innerObject = new InnerClass();
                > }
                >
                > class InnerClass
                > {
                > }
                > }[/color]

                Config 2:
                [color=blue]
                > class OuterClass
                > {[/color]
                // Now when you enumerate the fields of an instance of OuterClass you will find this field,
                // which just so happens to be of a Type that is NOT nested.
                // Using an instance of OuterClass, you can obtain an instance of InnerClass through this field
                // (if it is not set to null).
                InnerClass innerObject = new InnerClass();
                [color=blue]
                > OuterClass() // constructor
                > {[/color]
                // Same as the line in the constructor of config 1.[color=blue]
                > InnerClass innerObject = new InnerClass();
                > }
                > }
                >
                >[/color]
                // True, it may be declared in a seperate file :)
                // I believe in 2.0 you can actually redeclare the same class in multiple files and the compiler
                // will mix there implementation into one class template. I read that a while ago, so I'm not
                // sure if 2.0 will actually allow it, but it's worth mentioning just in case.[color=blue]
                > class InnerClass // Could even be in a separate file
                > {
                > }[/color]


                --
                Dave Sexton
                dave@www..jwaon line..com
                -----------------------------------------------------------------------
                "Robert W." <RobertW@discus sions.microsoft .com> wrote in message news:C279F1AB-7E22-4B6D-9B16-6E1BA824DB58@mi crosoft.com...[color=blue]
                > Hi Dave,
                >
                > I was sick today and got absolutely nothing done work-wise. I meant to ask
                > you one other thing related to all this:
                >
                > When I first learned about nested classes I just assumed that an inner class
                > was essentially the child of the outer class. What I mean is that once
                > defined and once the inner class is instantiated (in the simple way that I
                > did it) in the outer class's constructor, that a parent-child relationship is
                > set up.
                >
                > This belief seemed to be reenforced when I learned how to use the FieldInfo
                > of Reflection to gather the structure of the class definition. So naturally,
                > I thought, if there's a relationship with the class definition then there'd
                > "obviously" be a relationship with the object created from these classes.
                >
                > But after seeing your code (which I still do have to test thoroughly and
                > implement myself) I began to wonder if the whole nested classes concept was
                > more a matter of simple visual convenience than anything else.
                >
                > For example, let's look at two scenarios:
                >
                > Configuration 1:
                >
                > class OuterClass
                > {
                > OuterClass() // constructor
                > {
                > InnerClass innerObject = new InnerClass();
                > }
                >
                > class InnerClass
                > {
                > }
                > }
                >
                >
                >
                > Configuration 1:
                >
                > class OuterClass
                > {
                > OuterClass() // constructor
                > {
                > InnerClass innerObject = new InnerClass();
                > }
                > }
                >
                >
                > class InnerClass // Could even be in a separate file
                > {
                > }
                >
                >
                >
                > After reviewing (and thinking about) your code I began to wonder if all of
                > my earlier assumptions were incorrect. In fact, in terms of an actual
                > parent-child relationship between the OuterObject and the InnerObject:
                > - There really is none, if configured as above, is there?
                > - There's really no difference between the two configurations above, is
                > there?
                >
                > I apologize if all of these seem like dumb (read "obvious") questions but
                > the articles and other explanations I've found on nested classes aren't very
                > comprehensive.
                >
                > Robert W.
                >
                >
                >
                >
                >
                > "Robert W." wrote:
                >[color=green]
                >> Dave,
                >>
                >> Above & beyond the call. Thank you so much!!!
                >>
                >> Being new to C# I need to thoroughly study your code more but I think my
                >> problem lies in that my "connection " between the ContainerObject and the
                >> NestedObject is much more limited than the way you did it.
                >>
                >> For all I did was the equivalent of this:
                >>
                >> public NestedClass NestedObject = new NestedClass();
                >>
                >>
                >> But I'm not beginning to think that my approach really doesn't provide any
                >> actual connection between the two classes. Your way does and I think
                >> provides me a solid path to my solution.
                >>
                >> Got to get some sleep now but will revisit tomorrow and respost here when I
                >> know more.
                >>
                >> Thank you again!
                >>
                >> Robert W.[/color]
                >[/color]


                Comment

                • Robert W.

                  #9
                  Re: Using Reflection With Nested Classes

                  Dave,

                  Just wanted to thank you again!!! It has been a long day of programming but
                  I've now reached a major milestone and it's all thanks to you getting me past
                  that nested classes hurdle.

                  What I've been able to do is successfully (and completely) build a generic
                  bi-directional automated synchronization mechanism for an MVC
                  (Model-View-Controller) type application.

                  I have a data model (parent class and series of nested classes, each of
                  which contain several properties). And I also have a Windows form with
                  dozens upon dozens of controls on it.

                  Rather than individually coding the event mechanisms for each form control
                  and associated model properties, instead I now just need to enter into each
                  form control's tag the following: "Property=Prop_ name" For radio button
                  groupings I can also add a "Value=Button_v alue".

                  And once this is done, every control that is tagged this way then is
                  automatically bound to its associated model property. What's really great is
                  that the synchronization works both ways. So if some external code sets a
                  property called "CanPrint" to true then the "CanPrint" checkbox (or radio
                  button pair) is automatically set accordingly.

                  While it's true that not every control/property will be this
                  straightforward , a great number of them are! And like I said above, I've
                  built it generically (OOP) so that I can use the same objects in the future!!

                  This C# is soooooooooooo much more powerful than VB. I love it! And when I
                  get stuck on something there are great people like you to help me out.

                  Thank you so much!!!!

                  Robert Werner

                  Vancouver, BC

                  Comment

                  Working...