8

I' ve been doing some programming lately and faced an issue which i found weird in c#. (at least for me)

public class Foo
{
    //whatever
    public class FooSpecificCollection : IList<Bar>
    {
         //implementation details
    }
    public FooSpecificCollection GetFoosStuff()
    {
         //return the collection
    }
}

I want the consumer of Foo to be able to obtain a reference to FooSpecificCollection, even perform some operations on it. Maybe even set it to some other property of Foo or smth like that, but not To be able to CREATE an instance of this class. (the only class that should be able to instatiate this collection should be Foo.

Is my request really that far-fetched? I know that people way smarter defined c# but shouldn't there be such an option that a parent class can create a nested class instance but nobody else can't.

So far I created a solution to make an abstract class, or interface available through the property and implement a concrete private class that is not available anywhere else.

Is this a correct way to handle such a situation.?

luckyluke
  • 1,553
  • 9
  • 16
  • possible duplicate : http://stackoverflow.com/questions/1664793/how-to-restrict-access-to-nested-class-member-to-enclosing-class – Thomas Levesque Mar 14 '10 at 02:34
  • Curious : is it the case there will be multiple instances of 'Foo, each with its own unique 'FooSpecificCollection ? – BillW Mar 14 '10 at 09:23
  • Yes, that's the case. Let's say every client will have a Foo instance (it will be created by factory at some precise time) and Foo will create a FooSpecificCollection for itself. I give access to foo specific collection so that people know what foo has in it, and I let them play with the items, but they should not be able to create one as it makes little sense. During the night I thought maybe I try to make this code with too much semantics:) – luckyluke Mar 14 '10 at 09:41

5 Answers5

4

Make your nested class private and make the return value of GetFoosStuff IList<Bar> instead of FooSpecificCollection.

Also, there's a good chance that deriving from List<Bar> is a bug.

Community
  • 1
  • 1
Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • I derive from a List not foo – luckyluke Mar 13 '10 at 22:15
  • sorry I meant IList of course. List would be the internal implementation. But that is not what the question is about. But thanks for vigilance:) – luckyluke Mar 13 '10 at 22:16
  • 1
    Just curious what you mean by "deriving from `List` is a bug". I looked at the link, but can't find anything that indicates a problem in deriving from `List` in itself. – Zach Johnson Mar 13 '10 at 22:17
  • 99% of the time when you are claiming something is a List, what you're actually trying to say is that it's an enumeration of T (IEnumerable). It works, but is bad design to be too specific in the return type. – Yuliy Mar 14 '10 at 05:18
4

The way embedded classes work is that they, as members of the outer class, get access to private members of that outer class. But not the other way around (what is what you want).

You can shield the constructor of FooSpecificCollection, but then the Factory has to be part of FooSpecificCollection itself. It could enlist the outer class:

public class Foo
{
    public class FooSpecificCollection : List<Bar>
    {
         private FooSpecificCollection ()   { }

         public static FooSpecificCollection GetFoosStuff()
         {
            var collection = new FooSpecificCollection ();
            PrepareFooSpecificCollection(collection);
            return collection;            
         }
    }

    private static void PrepareFooSpecificCollection(FooSpecificCollection collection)
    {
         //prepare the collection
    }
}
H H
  • 263,252
  • 30
  • 330
  • 514
  • probably You are right:) it resembles the factory pattern a lot (I thought about it actually). – luckyluke Mar 13 '10 at 22:29
  • Always learn something from your answers, thanks, Henk. In this case what happens if there are multiple instances of 'Foo ? – BillW Mar 14 '10 at 09:25
  • 1
    @BillW, if you really were to use this pattern you would probably have to pass an instance of Foo through GetFooStuff() and on to PrepareFooSpecificCollection(). – H H Mar 14 '10 at 09:47
3

If you are creating a library for others to use, you could make the constructor internal. Anyone outside the library will not be able to access it. If you are concerned about calling the constructor in your own project, just don't call it outside the parent class.

We create classes all the time which are not directly related to other classes, but the constructors don't have to be hidden from non-related classes. We (the programmers) know the the objects are not related so we don't ever create an instance of one in the other.

Zach Johnson
  • 23,678
  • 6
  • 69
  • 86
1

There is a solution but I don't think I would use it in my App :) The idea is to have derived class from FooSpecific which is private and can be used only inside Foo but has public constructor, so Foo can create its instances.

public class Foo
{
    //whatever
    public class FooSpecific
    {
        // Protected contructor.
        protected FooSpecific()
        {
        }

        // All other code in here.
    }

    // Private helper class used for initialization.
    private class FooSpecificInitHelper : FooSpecific
    {
        public FooSpecificInitHelper()
        {
        }
    }

    // Method in foo to create instaces of FooSpecific.
    private FooSpecific CreateFooSpecific()
    {
        return new FooSpecificInitHelper();
    }
}
Andrew Bezzub
  • 15,744
  • 7
  • 51
  • 73
0

No, and it doesn't really make sense.

I mean the whole point is so that you could potentially return other instances; but who will be deriving from that class anyway? Certainly not any other classes (Because that would be wrong, and imply it shouldn't be hidden inside the main class), so ...

Noon Silk
  • 54,084
  • 6
  • 88
  • 105
  • I want to have some functionality in nested class that is clear and concise to read and use (ex nice interface on some internal collection of FOO). And I don't want to let people create that class. Of course they should have no business in that anyway, but I still would like a clear semantics that say - this class helps you operate on some Foo's stuff, but Foo gives it too you and you should not create it on your own... Internal is ok in a assembly but I don't get Your answer why it does not make sens. I want a developer using my class not to try instantiate it... why is that senseless? – luckyluke Mar 13 '10 at 22:14
  • There are other concerns than derived classes here. – H H Mar 13 '10 at 22:17
  • luckyluke: So make the constructor private? I thought you were trying to stop the outer class making an instance of it. – Noon Silk Mar 13 '10 at 23:23