Ngoài những lý do khác được liệt kê ở trên, có một lý do nữa mà tôi có thể nghĩ đến không chỉ để sử dụng các lớp lồng nhau, mà trên thực tế là các lớp lồng nhau công khai. Đối với những người làm việc với nhiều lớp chung có cùng tham số kiểu chung, khả năng khai báo một không gian tên chung sẽ cực kỳ hữu ích. Thật không may, .Net (hoặc ít nhất là C #) không hỗ trợ ý tưởng về không gian tên chung. Vì vậy, để thực hiện cùng một mục tiêu, chúng ta có thể sử dụng các lớp chung để thực hiện cùng một mục tiêu. Lấy các lớp ví dụ sau liên quan đến một thực thể logic:
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>
{
}
Chúng ta có thể đơn giản hóa chữ ký của các lớp này bằng cách sử dụng một không gian tên chung (được triển khai thông qua các lớp lồng nhau):
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 {}
}
Sau đó, thông qua việc sử dụng các lớp từng phần như được đề xuất bởi Erik van Brakel trong một nhận xét trước đó, bạn có thể tách các lớp thành các tệp lồng nhau riêng biệt. Tôi khuyên bạn nên sử dụng tiện ích mở rộng Visual Studio như NestIn để hỗ trợ lồng các tệp lớp một phần. Điều này cho phép các tệp lớp "không gian tên" cũng được sử dụng để tổ chức các tệp lớp lồng nhau trong một thư mục theo cách tương tự.
Ví dụ:
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);
}
}
Các tệp trong trình khám phá giải pháp studio trực quan sau đó sẽ được sắp xếp như vậy:
Entity.cs
+ Entity.BaseDataObject.cs
+ Entity.BaseDataObjectList.cs
+ Entity.IBaseBusiness.cs
+ Entity.IBaseDataAccess.cs
Và bạn sẽ triển khai không gian tên chung như sau:
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 {}
}
Và các tệp sẽ được sắp xếp trong trình khám phá giải pháp như sau:
User.cs
+ User.DataObject.cs
+ User.DataObjectList.cs
+ User.IBusiness.cs
+ User.IDataAccess.cs
Trên đây là một ví dụ đơn giản về việc sử dụng lớp ngoài làm không gian tên chung. Trước đây, tôi đã xây dựng "không gian tên chung" chứa 9 tham số kiểu trở lên. Việc phải giữ cho các tham số kiểu đó được đồng bộ hóa trên chín kiểu mà tất cả những gì cần thiết để biết các tham số kiểu thật tẻ nhạt, đặc biệt là khi thêm một tham số mới. Việc sử dụng các không gian tên chung làm cho mã đó dễ quản lý và dễ đọc hơn.