Окрім інших перелічених вище причин, є ще одна причина, по якій я можу думати не лише про використання вкладених класів, але і фактично для загальнодоступних класів. Для тих, хто працює з декількома загальними класами, які мають однакові параметри загального типу, можливість оголошення загального простору імен була б надзвичайно корисною. На жаль, .Net (або принаймні C #) не підтримує ідею загальних просторів імен. Тож для досягнення тієї ж мети ми можемо використовувати загальні класи для виконання тієї самої мети. Візьмемо такі приклади класів, що стосуються логічної сутності:
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>
{
}
Ми можемо спростити підписи цих класів, використовуючи загальний простір імен (реалізований через вкладені класи):
public
partial class 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 {}
}
Потім, використовуючи часткові класи, як запропонував Ерік ван Брекель у попередньому коментарі, ви можете розділити класи на окремі вкладені файли. Я рекомендую використовувати розширення Visual Studio на зразок NestIn для підтримки вкладання файлів часткового класу. Це дозволяє також використовувати файли класу «Простір імен» для організації вкладених файлів класу у папку.
Наприклад:
Entity.cs
public
partial class 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
{
}
Entity.BaseDataObject.cs
partial class Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
public class BaseDataObject
{
public DataTimeOffset CreatedDateTime { get; set; }
public Guid CreatedById { get; set; }
public Guid Id { get; set; }
public DataTimeOffset LastUpdateDateTime { get; set; }
public Guid LastUpdatedById { get; set; }
public
static
implicit operator tDataObjectList(DataObject dataObject)
{
var returnList = new tDataObjectList();
returnList.Add((tDataObject) this);
return returnList;
}
}
}
Entity.BaseDataObjectList.cs
partial class Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
public class BaseDataObjectList : CollectionBase<tDataObject>
{
public tDataObjectList ShallowClone()
{
var returnList = new tDataObjectList();
returnList.AddRange(this);
return returnList;
}
}
}
Entity.IBaseBusiness.cs
partial class Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
public interface IBaseBusiness
{
tDataObjectList Load();
void Delete();
void Save(tDataObjectList data);
}
}
Entity.IBaseDataAccess.cs
partial class Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
public interface IBaseDataAccess
{
tDataObjectList Load();
void Delete();
void Save(tDataObjectList data);
}
}
Файли в досліднику рішень візуальної студії будуть потім організовані як такі:
Entity.cs
+ Entity.BaseDataObject.cs
+ Entity.BaseDataObjectList.cs
+ Entity.IBaseBusiness.cs
+ Entity.IBaseDataAccess.cs
І ви б реалізували загальний простір імен на зразок наступного:
User.cs
public
partial class User
:
Entity
<
User.DataObject,
User.DataObjectList,
User.IBusiness,
User.IDataAccess
>
{
}
User.DataObject.cs
partial class User
{
public class DataObject : BaseDataObject
{
public string UserName { get; set; }
public byte[] PasswordHash { get; set; }
public bool AccountIsEnabled { get; set; }
}
}
User.DataObjectList.cs
partial class User
{
public class DataObjectList : BaseDataObjectList {}
}
User.IBusiness.cs
partial class User
{
public interface IBusiness : IBaseBusiness {}
}
User.IDataAccess.cs
partial class User
{
public interface IDataAccess : IBaseDataAccess {}
}
А файли будуть організовані в провіднику рішень таким чином:
User.cs
+ User.DataObject.cs
+ User.DataObjectList.cs
+ User.IBusiness.cs
+ User.IDataAccess.cs
Наведене є простим прикладом використання зовнішнього класу як загального простору імен. У минулому я створив "загальні простори імен", що містять 9 або більше параметрів типу. Необхідність зберігати параметри типу синхронізовані через дев'ять типів, що все, що потрібно знати параметри типу, було втомливим, особливо при додаванні нового параметра. Використання загальних просторів імен робить цей код набагато більш керованим і читабельним.