Shadow
Shadow

Reputation: 2478

Hide implementation details from developers in single assembly

I want to decouple Foo from FooHandler. Also they should be registered by DI via assembly scanning. Therefore I have 3 types:

interface IFooHandler { // no type arguments, so it can be used by reflection
   void DoStuff(object foo); 
}

interface IFooHandler<TFoo>: IFooHandler { // TFoo tells us, what foo is it for
   void DoStuff(TFoo foo); // developers are happy with strongly typed foos
}

abstract class FooHandler<TFoo>: IFooHandler<TFoo> {
   void IFooHandler.DoStuff(object foo){
       DoStuff((TFoo)foo); // adapter of interface 2 to 1
   }
   abstract void DoStuff(TFoo foo); // for nice implementation
}

The problem with such design is that I cannot easly forbid other people in my assembly from using IFooHandler or IFooHandler<TFoo> directly. Using first is bad idea, because it will not be registered in DI and it will fail. Using second is bad idea, because you write useless boilerplate, already written in base class.

Is it reasonable, to add Obsolete attribute with error=True to prevent people from using these interfaces? Is there is better way to hide them (I cannot move them to another assembly and mark as internal).

Concrete example: Lets say we have webapplication, and in that panel on various types there are contexts (Foo) that are identify of list of options for given context. Lets say you have currency selection, and Foo is CurrencyList. Then you have CurrencyListProvider class, that takes CurrencyList, retrieves available currencies from database and returns to panel, so user can choose which currency he want use for transaction. I am using concrete types, so you may easily move over codebase with tools such as resharper, but inside these concrete types there are string traveling through http.

Upvotes: 0

Views: 166

Answers (1)

Stefan
Stefan

Reputation: 17658

Is it reasonable, to add Obsolete attribute with error=True to prevent people from using these interfaces?

No. If you are afraid somebody will access your implementation directly, this won't stop them. A side effect is that they will question your skills as developer.

Also they should be registered by DI via assembly scanning

This is where your pain lives. Assembly scanning is just that: check the assembly and create instances, preferably through a nice public constructor. So, if you don't drop this requirement it's going to be... too complicated.

If you where to drop this requirement, and I think you can, since you have 3 versions and need a mechanism to switch between them; consider to use a own factory.

Let your factory decide which version to return.

You could even use friend assemblies to protect the constructors.

the real answer:


Just make sure your documentation is complete. If people read that you discourage the use of a certain type, let them decide. If your assemblies are well documented it helps you:

  • a) maintain your code through time
  • b) to refer to the docs if somebody screws-up
  • c) help your users correctly use your library

I think it's the only logical thing to do and much more descent than marking things as obsolete.

Upvotes: 1

Related Questions