简体   繁体   中英

Assembly … internal & external namespacing

Got a quick question here. I've got an assembly being re-used by a few developers which contains various bits of functionality, but is technically split in various namespaces representing logical blocks of functionality.

Now, it's being offered with as few public namespaces as possible. Basically, the user shouldn't know (and currently doesn't know) which internal structure is being used for the class they're trying to use.

Let's say you have this:

  • NS1

    • NS11
    • Class 111
    • Class 112
    • NS Extensions
      • Extension Class 1
    • NS12
  • NS2

    • ...

Basically, the users know they use FrameworkName.NS1 for general functionality regarding NS1. Now, in this simple example I've put a class containing extension methods in a subnamespace extensions, so basically, if an end user tries to use the assembly he'd have to actually know the internal structure of the DLL to know the extension exists (it's one of those examples where intellisense doesn't tell you you know).

So bottom line ... right now I've got this assembly and internally (the VS project) I divide the project into logical folders as one would normally do, but I do not let the namespaces follow the folders. This way the assembly's split up into logical blocks that users know w/o having to know the inner structures and don't need to know there could be seperate namespaces for extensions and so on.

Now, personally I'd like it if I could let my code's namespaces follow my folder structure, but somehow map those subnamespaces to the main namespace at compile-time.

Is it possible somehow to achieve this 'redirection' as you will?

To put it simply, I want to be able to address NS1.NS11.Class111 publically as NS1.Class111 outside of the assembly while still maintaining a proper structure inside the assembly.

If you need to provide a 3rd party access to some internal code via different namespaces, I would abstract the data access out into either a separate assembly (that depends on the original one), or use a web service to offer the subset of functionality you want them to access.

You might be able to do something with attributes on each of your classes, though I imagine it would get pretty messy, pretty quickly.

There are a few ways to think about this. Coming from a VB.net background originally and C# more recently I have the following comments on the topic.

  1. The folder\\namespace convention isn't adopted in VB.
  2. How you are going to address code versioning and management.
  3. If other c# developers are brought in to supplement your team, they might find it hard to understand the namespace/folder diversion.
  4. You could put the parent namespace in csproj properties, under the Application "Default Namespace". This would allow you to share these common utility (folders) between projects via copy and paste inheritance or Source Control folders or subprojects. This allows NS1.Extensions and NS2.Extensions to include the same code.
  5. I wouldn't worry about "hiding" internal corporate API's too much unless it's a particularly hostile technical environment. Even your "Encrypt" methods should use the appropriate public/private key infrastructure to make it secure by design.
  6. If you look at how most frameworks break up there solution you will see a series of projects that include all the code for the namespaces like "Core", "Shared", "Common". Most of these developers are very smart, so if it's the way they do things, I would follow.
  7. Have you considered nugget to deploy to a "shared network folder" and setup all your developers to point VS to that location?
  8. Finally I've found that extensions and helper methods become very stable very quickly, so the code doesn't change too much. I push them out to folder included in my source control /library/MyBusinessName/NameOfService.1.0.0.0/ . Which the same folder structure that Nuget packages use, so I know when an edition of my core underlying corporate code or frameworks are in use.
  9. Finally, if your going to have your code move down the MVVM path (popular) and your see the value in dependency injection , then your going to have to include a lot of "interfaces" to help test your common shared code, which is a lot easier in a separate DLL/Project.

Personally I've worked with a team that imported all the underlying source code for every thing they referenced in there corporate software, so they could "change" anything. At the end of the day it created a unholy level of build complexity and scared the pants off me when debugging. Nuget provides a great and very popular model, one I've adopted for corporate "shared" code. If I need to "tweek" shared code, I do it in the solution/project separately, test it, deploy it and use source control or nugget to copy the files around.

Here is an idea: create wrapper classes for public use. it may be a bit inefficient (although JIT might take care of it) and relatively a bit more difficult to maintain, but if you are worried about your public APIs (which you should be) it might be a good option. Chaining a couple of calls won't be any concern in most cases and you would have a layer that is concerned with the public API, potentially allowing you to commit a few sins behind your façade (breaking some good software design rules for the sake of performance for example)

You can create your internal structure however you like:

namespace Framework.Cool.Internal
{
    internal class BeansWeWantToCook
    {
        internal bool Cook()
        {
            // cooking process
        }
    }
}

..then create a public wrapper for internal functionality with the namespaces you want to expose:

namespace Framework.Cool
{
    public class Beans
    {
        // omitted code for brevity
        public bool Cook()
        {
            return _beansWeWantToCook.Cook();
        }
    }
}

This would create a very conventional structure which wouldn't surprise anyone looking for a class browsing your application.

Another option is to adopt a project specific convention like keeping all your public classes at the root of your project for example.

BTW, I wouldn't do anything funny with compile or build time procedure. I think that would be too confusing especially for new comers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM