473,657 Members | 2,530 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Making constructor visible only to a certain class

This is a design question.

I have a project containing a dozen or so classes with protected
internal constructors.

My reason for having protected internal constructors is to prevent
classes in other assemblies from instantiating them. There is a factory
class that instantiates them. Only the factory should do so, because
some of these classes have subclasses that will be created instead. The
decision of which class to instantiate belongs to the factory.

I've got this working just fine, except one detail.

Because the constructors are protected internal, it's possible for
classes inside the project to by-pass the factory. It's not too hard to
ensure this doesn't happen, by checking manually within the project;
but it would be easier and safer if the compiler could catch this
mistake.

Ideally, I'd like the constructors to have a more restricted visibility
than "internal". I'd like to specify that only the factory can see
them. I.e., instead of this:

protected internal Foo() {}

I'd like to be be able to write:

protected visibleto(Facto ry) Foo() {}

Unfortunately, C# has extremely coarse-grained visiblity modifiers.

I can think of a couple of work-arounds:

Work-around 1. Declare the constructors protected and let the factory
use reflection to instantiate them.

Work-around 2. Declare a nested protected class within the factory for
each of the classes it instantiates. The nested classes would have
public constructors. Then only the factory, or its descendants, could
instantiate the classes. Exactly what I want!

Both solutions would be worse than the original problem. Reflection
(Work-around 1) kills type-safety, so I avoid it unless I absolutely
need it; besides, it's slow. Work-around 2, on the other hand, would be
a bad case of code-bloat.

Is there a decent solution to this in C#?

-- Peter Gummer
Feb 20 '06 #1
18 6508
It would be nice if there was a "friend" concept in c#. If I may ask, why
can you not trust the code within your own assembly?

"Peter Gummer" <pe************ ******@hotnospa mmail.com> wrote in message
news:ec******** ******@TK2MSFTN GP09.phx.gbl...
This is a design question.

I have a project containing a dozen or so classes with protected
internal constructors.

My reason for having protected internal constructors is to prevent
classes in other assemblies from instantiating them. There is a factory
class that instantiates them. Only the factory should do so, because
some of these classes have subclasses that will be created instead. The
decision of which class to instantiate belongs to the factory.

I've got this working just fine, except one detail.

Because the constructors are protected internal, it's possible for
classes inside the project to by-pass the factory. It's not too hard to
ensure this doesn't happen, by checking manually within the project;
but it would be easier and safer if the compiler could catch this
mistake.

Ideally, I'd like the constructors to have a more restricted visibility
than "internal". I'd like to specify that only the factory can see
them. I.e., instead of this:

protected internal Foo() {}

I'd like to be be able to write:

protected visibleto(Facto ry) Foo() {}

Unfortunately, C# has extremely coarse-grained visiblity modifiers.

I can think of a couple of work-arounds:

Work-around 1. Declare the constructors protected and let the factory
use reflection to instantiate them.

Work-around 2. Declare a nested protected class within the factory for
each of the classes it instantiates. The nested classes would have
public constructors. Then only the factory, or its descendants, could
instantiate the classes. Exactly what I want!

Both solutions would be worse than the original problem. Reflection
(Work-around 1) kills type-safety, so I avoid it unless I absolutely
need it; besides, it's slow. Work-around 2, on the other hand, would be
a bad case of code-bloat.

Is there a decent solution to this in C#?

-- Peter Gummer

Feb 20 '06 #2
Peter Rilling wrote:
It would be nice if there was a "friend" concept in c#. If I may
ask, why can you not trust the code within your own assembly?


Well, I can trust it only insofar as I am infallible. I am but human,
so I'm sure to make mistakes :-)

It would be very easy to forget to use the factory. New developers will
also have to learn that my design involves calling the factory. I have
documented the design, but if someone fails to read the documentation
then they will probably just write "new Foo()" instead of
"Factory.NewFoo ".

My preference is for Eiffel, not C++, so I was wishing for "selective
export" rather than "friend". But you get the idea.

-- Peter Gummer
Feb 20 '06 #3
"Peter Gummer" <pe************ ******@hotnospa mmail.com> a écrit dans le
message de news: ec************* *@TK2MSFTNGP09. phx.gbl...

| Because the constructors are protected internal, it's possible for
| classes inside the project to by-pass the factory. It's not too hard to
| ensure this doesn't happen, by checking manually within the project;
| but it would be easier and safer if the compiler could catch this
| mistake.

How about using the InternalsVisibl eTo attribute to allow one assembly
access to something internal from another assembly.

This means that you could declare your classes with internal constructors in
one assembly and the factory in a "friend" assembly. As long as the factory
is the only class in the "friend" assembly, then it will be the only class
that can instantiate your types.

Joanna

--
Joanna Carter [TeamB]
Consultant Software Engineer
Feb 20 '06 #4
Joanna Carter [TeamB] wrote:
"Peter Gummer" <pe************ ******@hotnospa mmail.com> a écrit dans le
message de news: ec************* *@TK2MSFTNGP09. phx.gbl...

| Because the constructors are protected internal, it's possible for
| classes inside the project to by-pass the factory. It's not too hard to
| ensure this doesn't happen, by checking manually within the project;
| but it would be easier and safer if the compiler could catch this
| mistake.

How about using the InternalsVisibl eTo attribute to allow one assembly
access to something internal from another assembly.

This means that you could declare your classes with internal constructors in
one assembly and the factory in a "friend" assembly. As long as the factory
is the only class in the "friend" assembly, then it will be the only class
that can instantiate your types.

Joanna


That's a cool one :-). I wish I knew that a year ago.

But this applies just for the complete type, not one of its fields. I
think the OPs intend was to declare just the ctors private.

Here's a way to make the just ctor private:

public class AA
{
private AA() { }
}

public static class AAFactory
{
public static AA CreateAA()
{
return (AA)Activator.C reateInstance(t ypeof(AA), true);
}
public static T Create<T>()
{
return (T)Activator.Cr eateInstance(ty peof(T), true);
}
}

AA a1 = AAFactory.Creat e<AA>();
AA a2 = AAFactory.Creat eAA();
However, if it is possible for the factory just to return a base class
or interface, Joannas aproach is the cleanest.

HTH,
Andy
--
To email me directly, please remove the *NO*SPAM* parts below:
*NO*SPAM*xmen40 @*NO*SPAM*gmx.n et
Feb 20 '06 #5

"Peter Gummer" <pe************ ******@hotnospa mmail.com> wrote in message
news:ec******** ******@TK2MSFTN GP09.phx.gbl...
This is a design question.

I have a project containing a dozen or so classes with protected
internal constructors.

My reason for having protected internal constructors is to prevent
classes in other assemblies from instantiating them. There is a factory
class that instantiates them. Only the factory should do so, because
some of these classes have subclasses that will be created instead. The
decision of which class to instantiate belongs to the factory.


"protected internal" allows calling by the ctors of derived classes which
doesn't sound like what you want.
Feb 20 '06 #6
Why not just make the constructors private and use the factory thing
everywhere?

One more thing, have you checked FxCop? I think you can make a rule in it
and it'll do the enforcement of not using "new" that you want in your
current approach. Just an idea.

Regards.

-Ab.

"Peter Gummer" <pe************ ******@hotnospa mmail.com> wrote in message
news:ec******** ******@TK2MSFTN GP09.phx.gbl...
This is a design question.

I have a project containing a dozen or so classes with protected
internal constructors.

My reason for having protected internal constructors is to prevent
classes in other assemblies from instantiating them. There is a factory
class that instantiates them. Only the factory should do so, because
some of these classes have subclasses that will be created instead. The
decision of which class to instantiate belongs to the factory.

I've got this working just fine, except one detail.

Because the constructors are protected internal, it's possible for
classes inside the project to by-pass the factory. It's not too hard to
ensure this doesn't happen, by checking manually within the project;
but it would be easier and safer if the compiler could catch this
mistake.

Ideally, I'd like the constructors to have a more restricted visibility
than "internal". I'd like to specify that only the factory can see
them. I.e., instead of this:

protected internal Foo() {}

I'd like to be be able to write:

protected visibleto(Facto ry) Foo() {}

Unfortunately, C# has extremely coarse-grained visiblity modifiers.

I can think of a couple of work-arounds:

Work-around 1. Declare the constructors protected and let the factory
use reflection to instantiate them.

Work-around 2. Declare a nested protected class within the factory for
each of the classes it instantiates. The nested classes would have
public constructors. Then only the factory, or its descendants, could
instantiate the classes. Exactly what I want!

Both solutions would be worse than the original problem. Reflection
(Work-around 1) kills type-safety, so I avoid it unless I absolutely
need it; besides, it's slow. Work-around 2, on the other hand, would be
a bad case of code-bloat.

Is there a decent solution to this in C#?

-- Peter Gummer

Feb 20 '06 #7
Nick Hounsome wrote:
"protected internal" allows calling by the ctors of derived classes
which doesn't sound like what you want.


That's exactly what I want.

I'm not trying to restrict the capabilities of subclasses. I'm trying
to restrict the capabilities of clients; i.e., I don't want other
objects to be able to instantiate the product classes. Only the factory
should instantiate them.

So no: I definitely do not want "internal"; "protected internal" is
closer to what I want. My problem is that "internal" is too crude a
mechanism; "protected" is just fine.

-- Peter Gummer
Feb 20 '06 #8
Abubakar wrote:
Why not just make the constructors private and use the factory thing
everywhere?


If I made the constructors "private" (or "protected" ), the factory
would not have access to the constructors, so it would be unable to
instantiate the product classes -- unless, of course, I used one of the
two work-arounds that I mentioned in my original post (i.e. reflection,
for which Andreas Mueller gave sample code, or writing a protected
subclass for each product class nested within the factory) -- both of
which cures I feel are worse than the original problem.

Am I missing something in your "private" suggestion?

Thanks for the FxCop idea. We might end up doing that. It's a pain,
though, having to use a tool like FxCop to overcome the deficiencies of
the language.

-- Peter Gummer
Feb 20 '06 #9
Joanna Carter [TeamB] wrote:
How about using the InternalsVisibl eTo attribute to allow one
assembly access to something internal from another assembly.

This means that you could declare your classes with internal
constructors in one assembly and the factory in a "friend" assembly.
As long as the factory is the only class in the "friend" assembly,
then it will be the only class that can instantiate your types.


Something like that might work. I didn't know about InternalsVisibl eTo.

I wouldn't make the constructors "internal", though. That's exactly
what I'm trying to prevent: products within the assembly creating each
other directly. If I simply made the constructors "protected" , then
your idea should work.

The idea of adding another project, containing nothing but the factory,
doesn't really appeal to me. I actually have several factories (a fact
I didn't mention earlier), so I'd finish up with several teensy-weensy
factory projects. My initial feeling is that this is another cure worse
than the original problem; but I'll think about it.

Thanks for the suggestion.

-- Peter Gummer
Feb 20 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

19
3563
by: Martin Oddman | last post by:
Hi, I have a compiling problem. Please take a look at the code below. I have an application that is built upon three tiers: one data tier (Foo.DataManager), one business tier (Foo.Kernel) and one web presentation tier (Foo.WebFiles). The data tier shall only be accessible thru the business tier so I do NOT want a reference to the data tier in the presentation tier. In the business tier I have a class with the name CategoryItem that...
20
4251
by: Ole Hanson | last post by:
I am accessing my database through an interface, to allow future substitution of the physical datastore - hence I would like to declare in my Interface that my DAL-objects implementing the interface and accessing the datastore MUST pass in a UserToken in the constructor of the object. Is this not possible? Am I forced to add the UserToken as a property on the object instead? /Ole
5
9129
by: Tarscher | last post by:
Hi all, I have a user control and a form. I want the user control to be visible when the form is shown. I haven't found a good webtutorial on this so maybee someone can help me out? regards Stijn
9
3175
by: tshad | last post by:
I have a datagrid that I want to add a new column to. This column will only be visible under certain conditions. So I want to set the column visible=false. Then when the right condition happens to change it to visible=true. You can't do that with a bound column (no ID), but you can create a templatecolumn with a label. To make these visible, I am going through each datagriditem and making them visible after I have bound the data to...
15
1898
by: Sam Kong | last post by:
Hello! I got recently intrigued with JavaScript's prototype-based object-orientation. However, I still don't understand the mechanism clearly. What's the difference between the following two? (1)
2
1786
by: libsfan01 | last post by:
hi! i have written a function to make visible elements with a certain id. however i intended it to be used to make visible multiple elements but it only appears to switch on the first element it comes to with that id. after that it appears to stop. i was wondering how i can adapt this function to make visible multiple elements, will i need a different way of referencing or can it be done through id? your thoughts are greatly...
5
2116
by: ffrugone | last post by:
My scenario involves two classes and a database. I have the classes "Broom" and "Closet". I want to use a static method from the "Closet" class to search the database for a matching "Broom". If it finds a matching "Broom", i want it to return a "Broom" object to the calling program. I want the static method to call the constructor for the "Broom" class. I want this static method, (and one other called "CreateBroom") to be the only...
10
2412
by: JosephLee | last post by:
In Inside C++ object Model, Lippman said there are four cases in which compile will sythesize a default constructor to initialize the member variables if the constructor is absent: 1. there is a virtual function; 2. virtual inheritance; 3.base class with explicit default constructor;
16
2394
by: Andrea Gavana | last post by:
Hi Diez & All, Do you mind explaining "why" you find it *buttugly*? I am asking just out of curiosity, obviously. I am so biased towards wxPython that I won't make any comment on this thread in particular, but I am curious to know why some people find it "ugly" or "bad" or whatever. It has its own bugs and missing features, of course, but it is one of the major GUI player in the arena, together with PyQt and PyGTK.
0
8324
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8842
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8513
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8617
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
6176
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4173
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4330
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2742
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
1733
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.