How to allow instanciation of a class from another class method inside the same assembly???

  • Thread starter Thread starter Bob Rock
  • Start date Start date
B

Bob Rock

Hello,

I'd like to be able to allow instanciation of a class (class Class_A) only
from another class method (class Class_B). And I'd like to write the
necessary code to enforce this behavior even inside the same assembly where
class Class_A and Class_B are defined.
I've written the code that does this BUT I'd like to understand if this is
the most correct way to obtain such a result.

This is my simplified code:

// abstract class
public abstract class Class_C
{
public abstract void Method_1();
}

public class Class_B
{
// method that returns instances of class Class_A
public Class_A Method_2()
{
return new Class_A();
}

// nested private class - implements the abstract class Class_C
private class Class_A : Class_C
{
public override void Method_1
{
// implementation code
}
}
}

The above implentation allows the writing of the following "client" code:

Class_B b = new Class_B();
Class_C c = b.Method_2(); // creating an instance of class Class_A
c.Method_1(); // calling Method_1() of class Class_A

This code works well, the only thing I don't like is that Class_A is
completely unknown by code outside class Class_B.
Instead of an abstract class I could have used an interface but, since I
won't need to implement that interface more than once, I thought using an
abstract class to hold a reference to an instance of class Class_A to be
more correct.

Can anyone review this approach and tell me if there is any better solution?


Bob Rock
 
Hi Bob,

Well, your code does not compile :P (or at least did not for me). Something about the return type being less accessible than the method. However, changing the return type for Method_1 to Class_C will do the trick, but I suspect you did so already.

There is another approach of controlled instantiation which only involves one class.

public class Class_A
{
private Class_A()
{
}

public void Method_1()
{
}

public static Class_A Method_2()
{
return new Class_A();
}

}



Happy coding!
Morten Wennevik [C# MVP]
 
Hi Bob,
Well, your code does not compile :P (or at least did not for me).
Something about the return type being less accessible than the method.
However, changing the return type for Method_1 to Class_C will do the trick,
but I suspect you did so already.
There is another approach of controlled instantiation which only involves one class.

public class Class_A
{
private Class_A()
{
}

public void Method_1()
{
}

public static Class_A Method_2()
{
return new Class_A();
}

}


Happy coding!
Morten Wennevik [C# MVP]


Morten,

I'm sorry, I had to clean up my code to make the post and made a mistake.
Method_1 indeed returns an instance of Class_C.

Morten thank you for your code but it is not what I was asking for.
I'd like a class method (class Class_B method) to be the only one able to
return instances of a ANOTHER class (class Class_A).


Bob Rock
 
As Morton has shown you, you can prevent a class from being instanciated
from outside its type by making it's constructer private to its' class. That
is essentially what you want. Remember that your class C needs to be public
in order to assign that type to the reference pointer. I know you want one
class to be the ONLY ONE to be able to return objects of another type but
from what I see there are 2 problems to this.

1. To force a type to be inherited you would make it abstract, but by making
it abstract you cannot instanciate objects of its type (which you need to
do)
2. By hiding the constructor from outside the type you are preventing the
class from being inherited, which prevents you from returning an object of
its type from outside its class using the base object

Morton way to have a type become it's own object factory is the best way to
do what you what (as far as I can figure out). Please see code.

using System;

namespace ConsoleApplication1
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class ClassC
{
public void SayHello()
{
Console.WriteLine("Hello");
}

private ClassC()
{
//constructor is only visible within its own type
}

public static ClassC ReturnC()
{
return new ClassC();
}


}

public class AppStart
{
[STAThread]
static void Main(string[] args)
{
//ClassC c = new ClassC(); //would fail
//c.SayHello();
ClassC c = ClassC.ReturnC();
c.SayHello();
}
}
}

--

Br,
Mark Broadbent
mcdba , mcse+i
=============
Bob Rock said:
Hi Bob,

Well, your code does not compile :P (or at least did not for me).
Something about the return type being less accessible than the method.
However, changing the return type for Method_1 to Class_C will do the trick,
but I suspect you did so already.
There is another approach of controlled instantiation which only
involves
one class.
public class Class_A
{
private Class_A()
{
}

public void Method_1()
{
}

public static Class_A Method_2()
{
return new Class_A();
}

}


Happy coding!
Morten Wennevik [C# MVP]


Morten,

I'm sorry, I had to clean up my code to make the post and made a mistake.
Method_1 indeed returns an instance of Class_C.

Morten thank you for your code but it is not what I was asking for.
I'd like a class method (class Class_B method) to be the only one able to
return instances of a ANOTHER class (class Class_A).


Bob Rock
 
I think he wants to force PersonA to only be able to instanciate object of
ClassC via ClassA. Your method like mine is doing it through ClassC albeit
from ClassD itself. I believe that *exactly* what Bob wants is probably not
possible.

--

--

Br,
Mark Broadbent
mcdba , mcse+i
=============
Jakob Christensen said:
Hey Bob,

The following code will also work (with 2 classes only) because nested
classes have access to private fields of the classes they are nested within:
 
2. By hiding the constructor from outside the type you are preventing the
class from being inherited, which prevents you from returning an object of
its type from outside its class using the base object

This point is not exactly clear to me.

Bob Rock
 
Bob, another avenue that you could take for this kind of behaviour is to
only allow the instanciation of ClassC if and only if an instance of ClassA
is passed to it. You could then do validaty checking on the ClassA object if
necessary.

e.g.
using System;

namespace ConsoleApplication1
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class ClassC
{
public void SayHello()
{
Console.WriteLine("Hello");
}

public ClassC(ClassB key)
{
//constructor must have instance of ClassB passed to it otherwise compile
time error will occur
//in order to return error at run time instead you could Add back a
public ClassC() constructor
//and throw an exception in it.
}


}

public class ClassB
{
//any implementation you require
}

public class AppStart
{
[STAThread]
static void Main(string[] args)
{
//ClassC c = new ClassC(); //would fail
//c.SayHello();

ClassC c = new ClassC(new ClassB());
c.SayHello();

Console.ReadLine();
}
}
}

--

--

Br,
Mark Broadbent
mcdba , mcse+i
=============
Bob Rock said:
Hi Bob,

Well, your code does not compile :P (or at least did not for me).
Something about the return type being less accessible than the method.
However, changing the return type for Method_1 to Class_C will do the trick,
but I suspect you did so already.
There is another approach of controlled instantiation which only
involves
one class.
public class Class_A
{
private Class_A()
{
}

public void Method_1()
{
}

public static Class_A Method_2()
{
return new Class_A();
}

}


Happy coding!
Morten Wennevik [C# MVP]


Morten,

I'm sorry, I had to clean up my code to make the post and made a mistake.
Method_1 indeed returns an instance of Class_C.

Morten thank you for your code but it is not what I was asking for.
I'd like a class method (class Class_B method) to be the only one able to
return instances of a ANOTHER class (class Class_A).


Bob Rock
 
I think he wants to force PersonA to only be able to instanciate object of
ClassC via ClassA. Your method like mine is doing it through ClassC albeit
from ClassD itself. I believe that *exactly* what Bob wants is probably not
possible.

What I want is indeed very simple: I want a class (the manager class) to be
the only able to return instances of another class (the managed class).

Bob Rock
 
Mark, thank you for your effort.
Anyhow I identifies another possible solution that removes the "problem" of
the abstract class.


// -- the managed class
public class ManagedClass
{
// -- non public constructor
protected ManagedClass()
{

}
}

// -- the manager class
public class ManagerClass
{
// -- method returning an instance of managed class
public ManagedClass CreateInstance()
{
return new PrivateManagedClass();
}

// -- nested class
private PrivateManagedClass : ManagedClass
{
public PrivateManagedClass() : base()
{

}
}
}

Why not have ManagerClass directly inherit from ManagedClass? Because I
don't want to expose ManagedClass methods on ManagerClass.


Bob Rock
 
Ill try to explain better.

Imagine that we got ClassC and we have found a way to stop it being
constructed outside of ClassC *except* we need to find a way to allow ClassB
to instanciate it. My thoughts were that we could create a public (non
static) method (within ClassC) that returns an object instance of type C.
Obviously the method is non static and so it can only be called through an
instance of ClassC (which we have just said cannot be done on its own)
HOWEVER I thought why not inherit ClassC into ClassB allowing us to call
the method (and return a type instance) through base.MethodName().
Unfortunately since the ClassC constructor is private, that in itself
prevents the class being inherited, and therefore the pack of cards comes
falling down again.

Hope I made more sense that time?

--

--

Br,
Mark Broadbent
mcdba , mcse+i
=============
 
Imagine that we got ClassC and we have found a way to stop it being
constructed outside of ClassC *except* we need to find a way to allow ClassB
to instanciate it. My thoughts were that we could create a public (non
static) method (within ClassC) that returns an object instance of type C.
Obviously the method is non static and so it can only be called through an
instance of ClassC (which we have just said cannot be done on its own)
HOWEVER I thought why not inherit ClassC into ClassB allowing us to call
the method (and return a type instance) through base.MethodName().
Unfortunately since the ClassC constructor is private, that in itself
prevents the class being inherited, and therefore the pack of cards comes
falling down again.

Clear. A protected constructor would do the job.

Bob Rock
 
yes well done! a protected constructor gets around this issue. The only
potential problem I can see with all this, is that if the ManagedClass has
public members, then they will be accessible through the ManagerClass
instance (because they will be inherited).
Anyway you seem to have got where you wanted so I'll sign off for now.

bye.

--

--

Br,
Mark Broadbent
mcdba , mcse+i
=============
 
yes well done! a protected constructor gets around this issue. The only
potential problem I can see with all this, is that if the ManagedClass has
public members, then they will be accessible through the ManagerClass
instance (because they will be inherited).
Anyway you seem to have got where you wanted so I'll sign off for now.

Mark there is no such issue.
The manager class DOES NOT inherit from the managed class, the private
nested class inside the manager class is inheriting.


Bob Rock
 
sorry yes, didnt look at your code listing long enough, was still playing
with my code!
Anyway well done.


--

--

Br,
Mark Broadbent
mcdba , mcse+i
=============
 
Back
Top