Harlan said:
I found a couple of interesting approaches (along with a couple that
fall short by suggesting the use of *internal*) here:
http://stackoverflow.com/questions/...ess-to-nested-class-member-to-enclosing-class
Note that that question really isn't exactly the same as the OP here.
Specifically, if we assume a particular solution to the question in the
OP, then yes...the above question is appropriate, because it answers a
question about the implementation detail (and of course in the same way
I replied earlier).
But it doesn't really get at what might be a more significant issue,
related to the specific question in the OP.
Two people suggest creating a public interface for B to implement and
then making B private. Another came up with a method that I don't quite
understand yet that involves a static initialization block and a lambda
expression.
The lambda-based solution is difficult to understand because the person
who wrote it failed to provide all of the details, and the details he
did provide aren't actually quite right.
What that code is doing is creating a delegate representing a factory
method that can instantiate the class with the private constructor, and
storing a reference to that in the outer class where the Journal class
can get at it, but no other code can.
That way, the nested class can be public (so any code can see the type
and use public members of the type), but the constructor itself is
private, preventing ANY class from simply instantiating the type
directly (even the outer class). The outer class can instantiate only
by going through the factory method, and it's the only class that can
see the factory method.
It takes advantage of the fact that the nested class can access private
members of the outer class, and in doing so inverts the usual
relationship between the classes with respect to method visibility.
This would probably have been more obvious if the person had shown the
outer class actually _using_ the delegate. It's left to the reader to
infer that usage.
It's a reasonably clever solution, but does have its own problems: that
a) the interface implemented by the nested class is tied to the class
itself, and b) every constructor in the nested class needs a
corresponding factory method delegate to go with it, and a delegate type
variable in the outer class to store the delegate. It also has the
particularly egregious flaw that it's dependent on the order in which
the code executes, and what types are accessed.
In particular, the static initializer shown (which has the wrong syntax,
by the way...the code as shown won't even compile) isn't going to
execute until the inner type is actually accessed somehow. If you just
try to get an instance of the inner class from the outer class without
doing something to force the inner class to run its static initializer,
then the factory method delegate is never created and so can't be invoked.
This can be addressed by providing a dummy method in the inner class to
force the initialization. But then you've got this useless dummy method
in the inner class that necessarily is public and so visible to everyone
for no good reason.
I prefer the interface approach because it specifically avoids all of
the above problems.
![Smile :) :)](/styles/default/custom/smilies/smile.gif)
But, if you're curious, I've copied a complete
code example below that I wrote showing exactly how the factory delegate
approach works.
Pete
using System;
namespace TestPublicFactoryNestedClass
{
class Outer
{
public class Inner
{
static Inner()
{
_funcInnerFactory = delegate { return new Inner(); };
}
public static void InitType() { }
private Inner()
{
}
}
private static Func<Inner> _funcInnerFactory;
public static Inner CreateInner()
{
// Must be called to ensure that _funcInnerFactory is
// initialized!
if (_funcInnerFactory == null)
{
Inner.InitType();
}
return _funcInnerFactory();
}
}
class Program
{
static void Main(string[] args)
{
Outer.Inner inner = Outer.CreateInner();
}
}
}