17

I'm learning C# and coming from a Java world, I was a little confused to see that C# doesn't have a "package private". Most comments I've seen regarding this amount to "You cannot do it; the language wasn't designed this way". I also saw some workarounds that involve internal and partial along with comments that said these workarounds go against the language's design.

Why was C# designed this way? Also, how would I do something like the following: I have a Product class and a ProductInstance class. The only way I want a ProductInstance to be created is via a factory method in the Product class. In Java, I would put ProductInstance in the same package as Product, but make its constructor package private so that only Product would have access to it. This way, anyone who wants to create a ProductInstance can only do so via the factory method in the Product class. How would I accomplish the same thing in C#?

Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
  • 2
    Make the Product classes constructor Private, then have a Public Static Function that returns a ProductInstance, eg: var p = Product.GetProductInstance – Jeremy Thompson Feb 11 '11 at 02:01
  • 4
    Looking at the answers, I see no answer to the why. I feel it is a big code smell setting a method `internal` where it is intended to be used only by a few "friendly" classes (see the `friend` keyword in C++). I don't want to break my application into hundreds of dll just to prevent smelly access, nor do I like to leave my detail implementation open (basically public to the whole dev team). Should I write giant classes with ten subclasses to overcome this limitation? – PPC Feb 15 '13 at 17:35

2 Answers2

35

internal is what you are after. It means the member is accessible by any class in the same assembly. There is nothing wrong with using it for this purpose (Product & ProductInstance), and is one of the things for which it was designed. C# chose not to make namespaces significant -- they are used for organization, not to determine what types can see one another, as in java with package private.

partial is nothing at all like internal or package private. It is simply a way to split the implementation of a class into multiple files, with some extensibility options thrown in for good measure.

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
  • So I just need to mark `ProductInstance`'s constructor as `internal`? – Vivin Paliath Feb 11 '11 at 02:02
  • @Vivin, yes, and presumably the class as well. – Kirk Woll Feb 11 '11 at 02:06
  • No, creating an assembly for just one factory class is bad advice. Having hundreds of assemblies makes a project hard to manage. – miguel Jan 19 '18 at 02:15
  • @miguel, that you have conflated my answer into advising one create a separate assembly for each class is rather surprising. – Kirk Woll Jan 19 '18 at 15:12
  • When you said "There is nothing wrong with using it for this purpose (Product & ProductInstance)" I took it to mean that you should create an assembly for this one purpose. – miguel Jan 19 '18 at 18:56
  • @miguel, I'm really confused by why you think the use of internal implies creating more assemblies. In fact, without jumping through hoops (`[InternalsVisibleTo]`) splitting classes into separate assemblies _prohibits_ you from using `internal`. – Kirk Woll Jan 20 '18 at 00:12
  • OP's goal: The only way to create `ProductInstance` is via `Product.factory`. Your answer: use `internal`. But `internal` will still allow `ProductInstance` to be created via its constructor by other classes in the assembly. Therefore the only way your answer makes any sense is if `Product` and `ProductInstnace` are in their own assembly. – miguel Jan 24 '18 at 21:08
9

Packages don't really exist in the same way as they do in Java. Namespaces are used to organize code and prevent naming clashes, but not for access control. Projects/assemblies can be used for access control, but you can't have nested projects/assemblies like you can with packages.

Use internal to hide one project's members from another.

Martin Doms
  • 8,598
  • 11
  • 43
  • 60