.Net Loophole? (by way of delegates)

B

Brad

Question for all: Would one consider this a loophole in .net with respect
to nested (inner) classes?



1) Create outer class Foo and create a nested class Yin (inside Foo's class
definition ofcourse).
2) Let Foo have non-static protected (or public) method Bar() and Yin have a
non-static method called Yang().
4) Add a member object to Foo of Class Yin called yinObj.
5) Create an Object of Class Foo called fooObj.

Now if try to access from Foo's method Bar() from yinObj's (Yin's) method
Yang(), Visual Studio .Net compiler will correctly generate the error:
Cannot access a non-static member of outer type 'Foo' via nested type
'Foo\Yin'



However, I can get around this by creating a delegate BarWrapper which
serves as a wrapper function. All I do is the following:

A) Define Delegate BarWrapper from the scope of the outer class as public
delegate void BarWrapper.
B) Create instance of BarWrapper called BarWrap as a public member of nested
Class Yin.
C) Wrap Bar inside BarWrap in the Constructor of Foo as follows:
yinObj.BarWrap = new BarWrapper (Bar).
D) Place a call to BarWrap from within Yin's Method Yang as follows: Yang()
{ BarWrap(); }

Now when I compile, I will NOT get an error from the compiler. In effect I
have successfully accessed the non-static member function Bar from the
nested Class Yin.

Its as if I accomplished something the language was intending to prevent.

Is this a loophole in the language (as a result of the Delegate construct)
or is the ability to do what I did above intended?


Thanks,
Brad
 
G

Gary Morris

I haven't tried it, but it sounds suspicious. One of the things that I
am still trying to deal with is, the fact that anyone can disassemble
any .NET components and get a look at the contents. Not to mention
that if you get good at IL, you can reverse-engineer anything written.
Even the protections that are built-in like signing assemblies, etc.,
do not seem to be adequate if one knows enough IL to just break
down the app and all of it's dependancies, then recompile.

Granted, not many folks are going to spend the time to learn IL, much
less learn how to write "pure" .NET code with it, but it's not an
impossibility. I, personally, have even broken down protected apps
using the standard COM and normal compiled .exe's and "hacked"
them. If you can read assembler enough to find the protection and
loop around it or whatever, it's not too difficult to take a fully
functional
trial application and make it yours forever. Seems like .NET will make
this ever so much easier. At this point, worrying about class-level
protection seems like a moot point, given that we have complete
access to an assembly with IL. Not that you don't have a good point
here, I'm just looking beyond that.
 
J

Jon Skeet [C# MVP]

Now when I compile, I will NOT get an error from the compiler. In effect I
have successfully accessed the non-static member function Bar from the
nested Class Yin.

Yes, but only because that instance effectively has a route to know
about an instance of Foo, via the target of the delegate.
Its as if I accomplished something the language was intending to prevent.

I don't think so.
Is this a loophole in the language (as a result of the Delegate construct)
or is the ability to do what I did above intended?

Absolutely intended - and it has nothing to do with nested classes,
really. Unless, of course, I've misunderstood something. (It's late...)
Why do you think you shouldn't be able to do this?
 
B

Brad

Jon Skeet said:
Yes, but only because that instance effectively has a route to know
about an instance of Foo, via the target of the delegate.
prevent.

I don't think so.


Absolutely intended - and it has nothing to do with nested classes,
really. Unless, of course, I've misunderstood something. (It's late...)
Why do you think you shouldn't be able to do this?


My reasoning was this.
Some languages, like C or C++ allow going around certain error checks such
as type checking. In C, for instance, one can recast a pointer of any type
to a pointer of another type even if the data the pointer points to results
in it being out of bounds. I believe this was intentional.

Languages like C# and its predecessor Java seemed to have been created for
the purpose of minimize programming errors through strict rules on casting,
removal of reliance on freeing dynamically allocated memory, etc. If the
focus was to strictly enforce certain access rules, it seems that if the
compiler is telling me that nested classes are not allowed to access
non-static methods of the outer class (by treating it as a compiler error),
I would have expected that the language would have been designed in such as
way that it is not possible to specify an alternate route for the nested
class to know about the non-static method Bar. It seems that by wrapping up
a method in a delegate I can bypass the restrictions that are supposed to be
present.

Whether or not this is really important depends on the reason why nested
classes are not allowed to access non-static methods of an outer class. I
will need to look into that.

-Brad
 
M

Matthew W. Jackson

Could you just paste your source code of this "problem," since I cannot
follow your description. I tried to follow your example but you leave too
many things out. I may be interpreting a few things differently than you
meant us to.

But if this is about being able to access private methods using delegates,
then this is necessary, and there's nothing wrong with it. Otherwise you
couldn't write any event handlers. Example: private void
Button_Click(EventArgs e) is a private method *effectively* executed by the
Button class. However, this is only because the class containing the
Button_Click method *gave* it permission to do so via a delegate it created.

Indeed nested classes can access certain private members of their parent
class directly, but that's because they are just that: nested classes. They
belong to their parent class, so they have most of the rights that their
parent class does. The opposite is not true: the parent class does not have
direct access to the nested class's private members. This is by design, and
makes the most since with respect to how non-nested classes work.

Now if your parent class or nested class decides to give access to the
outside world, then that's entirely up to that class. This isn't a problem,
as the coder is still giving the access. Now, in your example, unless a
class outside of Foo and Yin can access the private methods by creating
their own delegate, then this may be a problem. As far as I know, though,
Foo or Yin would have to create the delegate and then pass it outside the
class. Once that happens, all bets are off when it comes to
private/public/protected.

But please post your code. I'm not understanding the problem. Like I said,
programmers NEED to be able to wrap a private method in a public delegate.
This is how the event-model works.

Now to really blow your mind.

I guess I shouldn't say this, but with Reflection, a programmer could access
private members of your class. Nothing is "completely private." I'm pretty
sure that .NET's Serializer accesses private data members to serialize
classes. And I'm absolutely sure that ValueType.Equals and
ValueType.GetHashCode do so as well (although they may not have to actually
use reflection, as this code is actually part of the CLR).

I've even seen a few nifty tricks that require accessing the private members
of some built-in .NET classes...it's not impossible--just a bad idea as the
private implementation is not required to stay the same between versions.

And if you want to say that this is the fault of IL then you are kidding
yourself. If you had a private function in a C or C++ program it could
certainly be called by outside code. All it takes is a function pointer.
I've seen cracks for anti-piracy routines that use this "flaw," such as
ken-generators that use a program's own private IsThisKeyValid() function to
check the keys it generates. IL may make it a bit easier since you have the
function's name and parameter types, but a good machine-assembly programmer
could figure these out in unmanaged code. At least in C# you can't
"accidentally" access a member you don't have rights to.

--Matthew W. Jackson
 
J

Jon Skeet [C# MVP]

Brad said:
My reasoning was this.
Some languages, like C or C++ allow going around certain error checks such
as type checking. In C, for instance, one can recast a pointer of any type
to a pointer of another type even if the data the pointer points to results
in it being out of bounds. I believe this was intentional.

Languages like C# and its predecessor Java seemed to have been created for
the purpose of minimize programming errors through strict rules on casting,
removal of reliance on freeing dynamically allocated memory, etc. If the
focus was to strictly enforce certain access rules, it seems that if the
compiler is telling me that nested classes are not allowed to access
non-static methods of the outer class (by treating it as a compiler error),
I would have expected that the language would have been designed in such as
way that it is not possible to specify an alternate route for the nested
class to know about the non-static method Bar.

But it wasn't that nested classes aren't allowed to access non-static
methods of the outer class - it's that they can't do so *directly*
without an instance of the outer class, because there's no implicit
instance for them to call the method on... just as you can't just call
an instance method from a static method within the same class. It's not
meant to be access control at all - it's just a case of "which instance
do you want me to call that method on?" If you provide an instance
reference, you can call the method directly.
 
B

Brad

Okay here is some sample code:

Case A:

namespace Ack
{
/// <summary>
///
/// </summary>
public class Foo
{
public Foo()
{
//
// TODO: Add constructor logic here
//
}

public void Bar()
{
Console.WriteLine("FooBar \n");
}

public class Yin
{
public Yin()
{

}

public void Yang()
{
Bar();
}
}
}
}

PRODUCES the following error when compiling:
.....App\Foo.cs(31): Cannot access a nonstatic member of outer type 'Ack.Foo'
via nested type 'Ack.Foo.Yin'


Case B:

namespace Ack
{
/// <summary>
///
/// </summary>
public class Foo
{
public Foo()
{
yinObj = new Yin();
yinObj.BarWrap = new BarWrapper(Bar);
}

public delegate void BarWrapper();

public void Bar()
{
Console.WriteLine("FooBar \n");
}

public class Yin
{
public Yin()
{

}

public BarWrapper BarWrap = null;

public void Yang()
{
BarWrap();
}

}

Yin yinObj;
}
}

PRODUCES no errors when compiling.

So with case B, the inner class now has access to method Bar.


I guess this is an intended consequence of the use of delegates, but I was a
little surprised I could bypass the restriction that nested classes are not
supposed to be allowed access to instance members of outer classes.

Anyway, This is not a big deal.

-Brad
 
M

Matthew W. Jackson

Ok you're missing a lot of things here. The first one won't compile, yes,
but it has nothing to do with public/private/protected access writes. It
has to do with non-static members. You CAN NEVER access a non-static member
without an object reference.

Example:

Foo.Bar() ;

This will NEVER work outside of the Foo class......it will INSIDE the class
but that is because there is an implied this reference. If you are using
that code INSIDE the Foo class it actually compiles to

this.Bar();

Where "this" refers to the current instance of the class. It could be any
instance.

You have to understand how non-static methods work. Think of them as
accepting an implied first parameter that is the object they are referring
to. If this were a non-OOP language (like C), the Bar method would look
something like this:

void Bar(Foo* obj)

Basically, when calling non-static methods, C# converts a call like this:

barObj.Bar();

To code that logically does the following:

Bar(&barObj);

The memory address of the object is automatically passed. Without it, you
cannot call a non-static method.


Going on...

You cannot access Foo.Bar from Foo.Yin because there is no instance of Foo
with which to do so. Just like you cannot simply call Object.GetHashCode();
You actually NEED an object with which to call this method because it is not
static.

Just because the Yin class is nested does not mean that when a Foo object is
created a Yin object is created as well (and vice versa). Therefore,
Foo.Yin cannot access any of Foo's non-static members because it does not
have an INSTANCE of Foo. It could however, do this:

Foo myFoo = new Foo();
myFoo.Bar();

This is the whole point of non-static members. If it were static you
wouldn't have to create an instance.

Actually the Foo object could even pass a reference to itself to the Foo.Yin
class. This is in effect what is happening when yoo create a delegate.

Furthermore, your second example doesn't actually break any rules or do
anything bad. Your Foo object is GIVING permission to access it's Bar
method. A (multicast) delgate contains (a list of) two things: a reference
to a member object and a reference to a method. If the first is null, then
the referenced method is a static method (since static methods do not
require the object reference).

When you declare this line:

public BarWrapper BarWrap = null;

BarWrap is not pointing to ANY function. Foo.Yin has not obtained access to
any method it should not be able to get to at this point. If you try to
call BarWrap in C# you will get an exception because there's nothing to
call.

Now in Yin's constructor you do this:

yinObj = new Yin();
yinObj.BarWrap = new BarWrapper(Bar);

In this case the Foo class is explicitly GIVING "permission" to Yin to be
able to call the following:

this.Bar();

Notice my emphasizing of the word "GIVING." The right to access that member
is never TAKEN from the Foo class. Without someone passing a reference to a
Foo object and the Bar method, the Foo.Yin class can never access it. Once
someone gives it a reference to a Foo object (in your case, it's the implied
*this* object), then certainly any class can access a public method.

This concept is KEY to the entire event model of .NET. Take the following
for example (i'm typing this off the top of my head so it may not actually
run):

public class MyForm : System.Windows.Forms.Form {

private System.Windows.Forms.Button myButton = new
System.Windows.Forms.Button();

public MyForm() {
myButton.Text = "OK";
myButton.Click += new EventHandler(myButton_Click); // this is
creating a delegate, btw
this.Controls.Add(myButton);
}

private void myButton_Click(object sender, EventArgs e) {
System.Windows.Forms.MessageBox.Show("Hello World!");
}

}


Now we obviously don't have the code to the Button class, but hopefully you
can see what's going on here. In this case, when the user clicks the
button, the Button class will call all delegates attached to the Click
event. In this case, the PRIVATE non-static function myButton_Click will be
called.

But the Button class has no RIGHT to call this myButton_Click method, right?
Not only does the Button class NOT have a reference to MyForm, but it can't
access this PRIVATE method. So how does this work?

Because the following line GIVES the Button class the right to do so.

myButton.Click += new EventHandler(myButton_Click);

Like I said, nothing is done without permission. This is not a bug. This
is not a design flaw. Otherwise, delegates would be rather useless. If you
had to make the myButton_Click method public and static, then ANYONE could
call it at ANY TIME. This is not what we want. We only want the
myButton.Click event to call this method. This is why it is marked private.

I hope my examples have helped. Please let us know if you are still unclear
on anything.

--Matthew W. Jackson
 
B

Brad

Thank you Mathew.
When I saw Jon Skeet's latest post, I then understood what my problem
was. I appreciated the in depth discussion on the use of static and
non-static members and the 'this' reference. However, I understood those
concepts already.

My problem was, as you pointed out, a misunderstanding of how nested classes
are handled. I incorrectly assumed that either: i) the nested class could
indirectly access the outer classes members by way of implicitly holding a
reference to the outer classes "this" pointer (Although come to think of it
I do not know how the compiler could accomplish that.) Or ii) For some
reason, nested classes in C# were not allowed to access non-static members
of their outer class. Since I got the compiler error I interpreted it the
second way rather than realizing it was just that there was simply no
mechanism to get a current instance of the outer class.

The key point I overlooked was as you put it: "Just because the Yin class is
nested does not mean that when a Foo object is created a Yin object is
created as well".

Again Thanks,
Brad
 
J

Jon Skeet [C# MVP]

I guess this is an intended consequence of the use of delegates, but I was a
little surprised I could bypass the restriction that nested classes are not
supposed to be allowed access to instance members of outer classes.

I'm sure all of this is just due to the compiler error not being as
clearly worded as it's meant to be. There *is* no restriction that
nested classes are not supposed to be allowed access to instance
members of outer classes - it's just that there is no implicit instance
of an outer class involved in an instance method of an inner class.
It's the equivalent of the error message "cannot access non-static
member from static context" or whatever it is you get if you try to
call an instance method from a static method within the same class
without using an instance of the class.
 
J

Jon Skeet [C# MVP]

Brad said:
My problem was, as you pointed out, a misunderstanding of how nested classes
are handled. I incorrectly assumed that either: i) the nested class could
indirectly access the outer classes members by way of implicitly holding a
reference to the outer classes "this" pointer (Although come to think of it
I do not know how the compiler could accomplish that.) Or ii) For some
reason, nested classes in C# were not allowed to access non-static members
of their outer class. Since I got the compiler error I interpreted it the
second way rather than realizing it was just that there was simply no
mechanism to get a current instance of the outer class.

The key point I overlooked was as you put it: "Just because the Yin class is
nested does not mean that when a Foo object is created a Yin object is
created as well".

Out of interest, are you also a Java programmer? If so, this could
easily be the root of the confusion - C# has no equivalent to Java's
inner classes, only nested classes. The C#

public class Outer
{
public class Inner
{
...
}

...
}

is the equivalent of the Java

public class Outer
{
public static class Inner
{
...
}

...
}
 

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