Questions tagged [parametric-namespaces]

Parametric or generic namespaces are a specialization of parametric polymorphism where type parameters are defined on an outer construct that itself contains types that share access to the type parameters.

Wikipedia defines a namespace as:

In computing, a namespace is a set of symbols that are used to organize objects of various kinds, so that these objects may be referred to by name.

Concept:

Parametric or generic namespaces are containers where by types defined within the container share visibility and access to type parameters for which arguments will be supplied at a later time. Typically, these types are logically related and define a package of related abstract functionality. These types if defined upon their own, would repeatedly define the same generic type parameters resulting in code that is potentially more unwieldy, difficult to maintain and less DRY.

Example:

Consider the following related types for example:

public  class       BaseDataObject
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

public  class       BaseDataObjectList
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
:   
                    CollectionBase<tDataObject>
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

public  interface   IBaseBusiness
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

public  interface   IBaseDataAccess
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

The code for the types can be simplified and DRYed up by leveraging a parametric namespace. For example:

namespace Entity
          <
              tDataObject, 
              tDataObjectList, 
              tBusiness, 
              tDataAccess
          >
where tDataObject     : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.BaseDataObject
where tDataObjectList : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.BaseDataObjectList, new()
where tBusiness       : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.IBaseBusiness
where tDataAccess     : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.IBaseDataAccess
{

    public  class       BaseDataObject {}

    public  class       BaseDataObjectList : CollectionBase<tDataObject> {}

    public  interface   IBaseBusiness {}

    public  interface   IBaseDataAccess {}

}

And then the parametric namespace and its contained types may be derived like this:

namespace User
:
          Entity
          <
              User.DataObject, 
              User.DataObjectList, 
              User.IBusiness, 
              User.IDataAccess
          >
{
    public  class       DataObject     : BaseDataObject     {}
    public  class       DataObjectList : BaseDataObjectList {}
    public  interface   IBusiness      : IBaseBusiness      {}
    public  interface   IDataAccess    : IBaseDataAccess    {}
}

namespace Article
:
          Entity
          <
              Article.DataObject, 
              Article.DataObjectList, 
              Article.IBusiness, 
              Article.IDataAccess
          >
{
    public  class       DataObject     : BaseDataObject     {}
    public  class       DataObjectList : BaseDataObjectList {}
    public  interface   IBusiness      : IBaseBusiness      {}
    public  interface   IDataAccess    : IBaseDataAccess    {}
}

Types from the specialized namespaces are then accessed as such:

public class Program
{
    static void Demo(User.IBusiness userBusiness, Article.IBusiness articleBusiness)
    {
        var users    = new User.DataObjectList();
        var user     = new User.DataObject();
        var articles = new Articles.DataObjectList();
        var article  = new Articles.DataObject();
    }
}

Benefits:

The benefits of the parametric namespace are as follows:

  1. Defines each type parameter only once across several related types;
  2. New type parameters are immediately visible across all contained types;
  3. Neatly packages parametric abstract functionality in the same way that classical namespaces provide, but with the added benefit of only having to specify type arguments once;
  4. Provides basic parametric polymorphism across an array of related types
  5. Provides and promotes uniformity of the contained type names across specialized derived namespaces.

Support:

As of yet, there is very little if any support for this concept in mainstream languages. However, this organization concept may still be possible to accomplish by way of a combination of parametric classes or interfaces and nested types. For example, in C#, you can define generic classes with type parameters that are then visible across all nested types contained within the generic class.

Questions and answers regarding the sharing of generic parameters across multiple types should have this tag applied.

Relevant links:

Generics on Stack Overflow

Wikipedia article on generics

Blog article on generic namespaces

3 questions
4
votes
2 answers

Generic delegate variable

I've hurt my brain here. Some background: I have a multiple services in multitier app. Some of them are short-living (and should be consumed with using) and some of them are not (so I just inject them in any class I want and use directly). My client…
Szer
  • 3,426
  • 3
  • 16
  • 36
1
vote
1 answer

Resolve DTO type into Domain type in WCF service

I have a WCF service which works with SQL through EntityFramework via net.tcp Its allowed to clients to query items by Id from Db. I have a plenty of methods which looks like this: public SiteDTO GetSiteById(long siteId) { using (var…
Szer
  • 3,426
  • 3
  • 16
  • 36
-1
votes
1 answer

How to properly declare a return type of a future subclass type of a related generic base class?

Someone is trying to achieve an abstraction in ASP.NET MVC with C#. They have a base entity controller which should do most of the job for its derived classes(entities). In it, they have a problematic method which should return the database context…
Tyree Jackson
  • 2,588
  • 16
  • 22