Using Reflection With Nested Classes

G

Guest

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.GetValue(ObjectMain.ObjectNested1, 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.ObjectNested1'

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
 
D

Dave

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

foreach (Type nested in type.GetNestedTypes())
Console.WriteLine(nested.FullName);

// Outputs the following:
/*
System.Environment+SpecialFolder
Press any key to continue
*/
}
 
D

Dave

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.Reflection.PropertyInfo objProp in obj.GetType().GetProperties())
{
if (objProp.CanRead)
{
object[] indexer = new object[0];
object nestedObj = objProp.GetValue(obj, indexer);

foreach (System.Reflection.PropertyInfo nestedProp in nestedObj.GetType().GetProperties())
{
if (nestedProp.CanRead)
{
Console.WriteLine("{0}.{1}={2}",
nestedProp.DeclaringType.FullName, nestedProp.Name,
nestedProp.GetValue(nestedObj, indexer));
}
}
}
}

// Outputs the following:
/*
TestConsole.ContainerClass+NestedClass.Property=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"; } }
}
}
}
 
G

Guest

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.ObjectNested1

Robert
 
D

Dave

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
[email protected]
-----------------------------------------------------------------------
Robert W. said:
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.ObjectNested1

Robert
 
G

Guest

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.
 
G

Guest

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.
 
D

Dave

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:
class OuterClass
{
// 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();
OuterClass() // constructor
{
// You won't be able to reflect this instance because it is confined to
// the implementation of the constructor.
InnerClass innerObject = new InnerClass();
}

class InnerClass
{
}
}

Config 2:
class OuterClass
{
// 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();
OuterClass() // constructor
{
// Same as the line in the constructor of config 1.
InnerClass innerObject = new InnerClass();
}
}
// 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.
class InnerClass // Could even be in a separate file
{
}
 
G

Guest

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_value".

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
www.mwtech.com
Vancouver, BC
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top