Je sais que c'est une vieille question, mais une raison très valable d'utiliser une classe comme espace de noms (un non statique à cela) est que C # ne prend pas en charge la définition des espaces de noms paramétriques ou génériques. J'ai rédigé un article de blog sur ce sujet ici: http://tyreejackson.com/generics-net-part5-generic-namespaces/ .
L'essentiel est que, lors de l'utilisation de génériques pour résumer d'énormes portions de code passe-partout, il est parfois nécessaire de partager plusieurs paramètres génériques entre des classes et des interfaces liées. La manière conventionnelle de le faire serait de redéfinir les paramètres génériques, les contraintes et tout cela dans chaque interface et signature de classe. Au fil du temps, cela peut entraîner une prolifération de paramètres et de contraintes, sans parler de devoir constamment qualifier les types associés en transmettant les paramètres de type d'un type aux arguments de type du type associé.
L'utilisation d'une classe générique externe et l'imbrication des types associés au sein peuvent considérablement assécher le code et simplifier son abstraction. On peut ensuite dériver la classe d'espace de noms paramétrique avec une implémentation concrète qui fournit tous les détails concrets.
Voici un exemple trivial:
public class Entity
<
TEntity,
TDataObject,
TDataObjectList,
TIBusiness,
TIDataAccess,
TIdKey
>
where TEntity : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>, subclassed
where TDataObject : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.BaseDataObject, subclassed
where TDataObjectList : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.BaseDataObjectList, subclassed
where TIBusiness : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.IBaseBusiness
where TIDataAccess : Entity<TEntity, TDataObject, TDataObjectList, TIBusiness, TIDataAccess, TIdKey>.IBaseDataAccess
{
public class BaseDataObject
{
public TIdKey Id { get; set; }
}
public class BaseDataObjectList : Collection<TDataObject> {}
public interface IBaseBusiness
{
TDataObject LoadById(TIdKey id);
TDataObjectList LoadAll();
void Save(TDataObject item);
void Save(TDataObjectList items);
void DeleteById(TIdKey id);
bool Validate(TDataObject item);
bool Validate(TDataObjectList items);
}
public interface IBaseDataAccess
{
TDataObject LoadById(TIdKey id);
TDataObjectList LoadAll();
void Save(TDataObject item);
void Save(TDataObjectList items);
void DeleteById(TIdKey id);
}
}
Utilisé comme ceci:
public class User
:
Entity
<
User,
User.DataObject,
User.DataObjectList,
User.IBusiness,
User.IDataAccess,
Guid
>
{
public class DataObject : BaseDataObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class DataObjectList : BaseDataObjectList {}
public interface IBusiness : IBaseBusiness
{
void DeactivateUserById(Guid id);
}
public interface IDataAcccess : IBaseDataAccess {}
}
Consommez les dérivés comme ceci:
public class EntityConsumer
{
private User.IBusiness userBusiness;
private Permission.IBusiness permissionBusiness;
public EntityConsumer(User.IBusiness userBusiness, Permission.IBusiness permissionBusiness) { /* assign dependencies */ }
public void ConsumeEntities()
{
var users = new User.DataObjectList();
var permissions = this.permissionBusiness.LoadAll();
users.Add
(new User.DataObject()
{
// Assign property values
});
this.userBusiness.Save(users);
}
}
L'avantage d'écrire les types de cette manière est une sécurité de type accrue et moins de transtypage de types dans les classes abstraites. C'est l'équivalent de ArrayList
vs List<T>
à plus grande échelle.