views:

176

answers:

7

I'm building a library where I've got a pattern like the following:

public class Foo : Foo_Impl
{
}

public class Foo_Impl
{
}

I don't want other developers to accidentally use the Foo_Impl class. What options are available to me to hide this? I'd also like to hide it from other classes in the same assembly it's defined in. Ideally I'd have loved to do:

public class Foo : Foo_Impl
{
  private class Foo_Impl
  {
  }
}

But that doesn't work for a variety of reasons.

+4  A: 

There is no way to completely hide it. If Foo is going to be public, its base class has to be public too. However, you can prevent other developers from creating an instance of Foo_Impl, by making the constructor protected. That way the constructor can only be used from derived classes.

public class Foo_Impl
{
    protected Foo_Impl()
    {
    }
}

public class Foo : Foo_Impl
{
    public Foo() // implicitly calls the base class's protected constructor
    {
    }
}

If you don't want people to be able to create their own classes derived from Foo_Impl, make the constructor internal

Thomas Levesque
+5  A: 

Make Foo_Impl an abstract class. This won't stop other developers from deriving from it, but it will make it impossible to create an instance of Foo_Impl directly - it will need to be instantiated by creating a derived object, such as Foo.

public abstract class Foo_Impl
{
    public Foo_Impl()
    {
    }
}

public class Foo : Foo_Impl
{
    public Foo() // implicitly calls the base class's constructor
    {
    }
}

-

var works = new Foo(); // Works
var error = new Foo_Impl(); // Compiler error

Per Thomas Levesque's suggestion, you also have the option of making the abstract constructor internal:

public abstract class Foo_Impl
{
    internal Foo_Impl()
    {
    }
}

public class Foo : Foo_Impl
{
    public Foo() // implicitly calls the base class's constructor
    {
    }
}

This will prevent developers from inheriting from Foo_Impl from outside the assembly.

Jake
you *can* stop other developers from deriving from it: just make the constructor internal
Thomas Levesque
This is the most appropriate semantic for preventing people from instantiating Foo_Impl() directly.
Michael
@Thomas-Levesque I was thinking in the same assembly, but I guess I should have mentioned that option.
Jake
Good points here. I had thought about Abstract, and I had thought about Internal, but I hadn't thought about an Abstract class with an Internal constructor. You, good sirs, have earned one internets.
Hounshell
+4  A: 

The options you have are:

  • Make Foo_Impl abstract. Developers will not be able to instantiate a Foo_Impl directly; they must declare a Foo. However, Foo_Impl can still be used as a method parameter or generic type parameter, and developers can derive their own classes from Foo_Impl.

  • Make Foo_Impl internal, and place both it and Foo in a seperate library from any other class you want to hide Foo_Impl from. Developers working outside that assembly will not be able to see Foo_Impl. However, developers may be able to reflect the type and instantiate one if they have sufficient CAS permissions in the runtime, and any developer with access to your assembly's source can new up a Foo_Impl within that assembly.

  • Make all constructors of Foo_Impl protected or internal. Protected constructors can only be accessed by derived classes, while internal constructors can only be accessed from within the same assembly. Either way, a Foo_Impl cannot be instantiated by an outsider. However, developers can still use the class as a parameter or generic type.

  • Mark Foo_Impl's constructors, or the whole class, as Obsolete using the [Obsolete] attribute, specifying that use of this class should trigger an error. It's kind of a hack, but you can both prevent compilation of "wrong" code, and use the Message parameter of the attribute to specify what SHOULD be used. However, take care what you decorate; if you decorate the entire class, I do not think the compiler will let you do ANYTHING with the class, including inherit from it. Decorating the constructors ought to stop most coders.

KeithS
+1 Very thorough. Just curious on the last item... wouldn't that prevent Foo from using Foo_Impl as well?
harpo
Your 2nd point is wrong: if you make Foo_Impl internal, then Foo can't be public. Otherwise, very good answer ;)
Thomas Levesque
+9  A: 

I haven't seen this suggested yet, so I thought I would add my $.02.

How about using composition instead of inheritance? An instance of Foo_Impl can be maintained by Foo and will never be visible to the outside world (because Foo_impl will be private to the assembly). Calls can be passed through the interface to Foo_Impl functions as needed. You get the same functionality and none of the design headaches.

private class Foo_Impl
{
    public void DoSomething() { }
}

public class Foo
{
    private Foo_Impl _implementation;

    public Foo() { _implementation = new Foo_Impl(); }

    public void DoSomething() { _implementation.DoSomething(); }
}

As far as "hiding it from other classes in the assembly", you could make it a nested class if you really felt that was appropriate.

Ed Swangren
I appreciate the suggestion and it's the first one I'd have given if I saw the question, but in this case I specifically need to have the inheritance
Hounshell
Why? Perhaps you do, or perhaps you are mentally locked into a single solution that may not be the best choice.
Ed Swangren
I'm generating some code. Ultimately I want the user to use class A while A_Impl provides the implementation. Some pieces of that implementation are stubs so that the user generated code can be triggered by other events. The classical model of that is what MS did with C# WinForms: providing events for pre/post behavior, but that means making a number of protected members public, handling the multicast scenarios, and documenting the threading model. Ultimately I want to sidestep the event mess and provide a higher level of encapsulation.
Hounshell
So you're right, I am mentally locked into that solution, but it's a choice I made knowing that this was the limitation of that decision path and I'm more willing to compromise with the answer I accepted than on that original decision.
Hounshell
+3  A: 

This might sound silly, but there's a very simple solution: document the correct usage. If Foo_Impl shouldn't be instantiated, then add a comment to the class saying so. Include it in any other documentation about the class, as well.

You can (and should) do this even if you implement one of the other solutions here.

Srayer
+1 Especially as it gives you the opportunity to state **why** it shouldn't be instantiated. Which probably is far more interesting and informative.
Marjan Venema
A: 

Ok, I think I have solved the riddle. You implement Foo_Impl in two partial parts.

One is public partial class Foo_Impl {} implementation which is basically an empty class doing nothing, so it will not be usable in any sense.

The other is implemented as a private partial class Foo_Impl{} member of the Foo:Foo_Impl class. Thats where you put all your secret functionality that can only be used by Foo itself. Any class can inherit from the public partial part of Foo_Impl but cannot use any of the private functionality only available to Foo through its private Foo_Impl memeber. An example class Voyeur:Foo_Impl is used to illustrate that every body can inherit but only Foo can instantiate and use it. Voyeur cannot peep into Foo_Impl to get a glimpse of its useful private parts ;) .

    using System;



    static class Program
    {


        static void Main(string[] args)
        {

            new Foo();
            new Voyeur();


            Console.ReadLine();

        }


    }


     public partial class Foo_Impl
    {
         // NOTHING in this public partial implementation. 
         // Visible but cannot be used for anything

        protected Foo_Impl()
        {
            Console.Write("public partial Foo_Impl's protected constructor ");
        }

    }



    public class Foo : Foo_Impl
    {
        private partial class Foo_Impl {

            // put all your secret implementations here that you dont want 
            // any other class to accidentally use (except Foo)

            public int fooAccessibleVariable=42;

            public Foo_Impl ()

            {
                Console.Write("private partial Foo_Impl contructor ");

            }



        }

        public Foo():base() // calls the public partial Foo_Impl's construtor
        {
            Console.WriteLine(" called from Foo()");


            Foo_Impl myFoo_Impl =  new Foo_Impl(); // calls the private partial Foo_Imp's constructor
            Console.WriteLine(" called from Foo()");

            Console.WriteLine("private Foo_Impl's variabe thats only accessible to Foo: {0}",
                myFoo_Impl.fooAccessibleVariable);
        }

    }

    class Voyeur:Foo_Impl
    {



        public Voyeur():base()// calls the public partial Foo_Impl's contructor 
        {

            Console.WriteLine("  called from Voyeur()");

        }


    }
mumtaz
+1  A: 

The abstract keyword is probably the most applicable to your scenario. Bear in mind that if you are providing an assembly (dll) that you want people to take advantage of a particular bit of functionality, you can implement the black box paradigm via Interfaces. If you provide the interface to be used and internally implement the interface, your assembly can provide the interface reference without handing over a reference to the instantiated class itself. All the developers would know are the properties and methods you've defined in the interface definition. This is highly common in plugin architectures.

Michael