Generic Abstract class 从 Passed Type Parameter 继承成员
Generic Abstract class who inherits members from Passed Type Parameter
我正在尝试找出一种方法来抽象我的适配器逻辑。我想要一个从传递给它的成员继承的通用摘要 class。
public interface IAdaptable<in TIEntity, in TIDTO, TDTO>
where TDTO : TIDTO
{
void Initialize(TIEntity entity);
TDTO ToDTO();
}
public interface IAdaptable<in TIEntity, TDTO> : IAdaptable<TIEntity, TDTO, TDTO>
{
}
public abstract class AdapterBase<TEntity, TIDTO, TDTO> : IAdaptable<TEntity, TIDTO, TDTO>, TIDTO
where TDTO : TIDTO
{
protected TEntity entity;
public void Initialize(TEntity entity)
{
this.entity = entity;
}
public TDTO ToDTO()
{
return Mapper.Map<TIDTO, TDTO>(this);
}
}
此代码不起作用,因为您不能从传入的通用参数继承,即使 id 像我的父 class 一样强制执行它。
如果有人想知道为什么或这里发生了什么,这个适配器基础应用于必须实现 DTO 接口属性的适配器,然后将附加逻辑应用于 getter 和设置以防止 id 篡改和做一些基本的设置逻辑。
如果我手动将此代码应用于每个适配器,则此代码工作正常,但我更喜欢适配器基础或代理而不是适配器基础,后者将为我处理所有这些逻辑。
有谁知道我可以抽象出这个逻辑的方法,或者解决方法,这样我就不必手动将这个逻辑应用到每个适配器?
对于那些想要答案的人,我找到了一个解决方案,但你可能不喜欢它。
这是完整界面:
public interface IAdaptable<in TIEntity, in TIDTO, TDTO>
where TDTO : TIDTO
{
bool IsInitialized { get; set; }
void Initialize(TIEntity entity);
TDTO ToDTO(TIDTO iEntityDTO);
void ApplyFrom(TIDTO entityDTO);
}
现在您可以像这样创建适配器基础:
public class AdapterBase<TIEntity, TIDTO, TDTO> : IAdaptable<TIEntity, TIDTO, TDTO>
where TDTO : TIDTO
{
#region Consts
public const string FAILED_TO_INITIALIZE_ADAPTER_ERROR = "Failed to Initialize Adapter make sure you called the Initialize function";
#endregion
#region Protected Members
protected TIEntity _entity;
#endregion
#region IAdaptable
public bool IsInitialized { get; set; }
public void Initialize(TIEntity entity)
{
this._entity = entity;
IsInitialized = true;
}
public void ApplyFrom(TIDTO entityDTO)
{
if (false == IsInitialized)
{
throw new Exception(FAILED_TO_INITIALIZE_ADAPTER_ERROR);
}
Mapper.Map(entityDTO, this);
}
public TDTO ToDTO(TIDTO adaptable)
{
if (false == IsInitialized)
{
throw new Exception(FAILED_TO_INITIALIZE_ADAPTER_ERROR);
}
return Mapper.Map<TIDTO, TDTO>(adaptable);
}
#endregion
}
现在您可以像这样在通用的 crud 服务中使用您的适配器
public class AsyncCRUDService<TEntity, TIDTO, TDTO, TAdapter> : IAsyncCRUDService<TDTO>
where TDTO : TIDTO
where TEntity : class, new()
where TAdapter : class, TIDTO, IAdaptable<TEntity, TIDTO, TDTO>
{
protected DbContext _context;
protected TAdapter _adapter;
public AsyncCRUDService(DbContext context, TAdapter adapter)
{
this._context = context;
this._adapter = adapter;
}
public async virtual Task<TDTO> Get(object[] id)
{
var entity = await this._context.Set<TEntity>().FindAsync(id);
if (null == entity)
{
throw new InvalidIdException();
}
return this.AdaptToDTO(entity);
}
protected virtual TDTO AdaptToDTO(TEntity entity)
{
this._adapter.Initialize(entity);
return this._adapter.ToDTO(this._adapter);
}
}
唯一的缺点是现在您的服务依赖于硬依赖
我正在尝试找出一种方法来抽象我的适配器逻辑。我想要一个从传递给它的成员继承的通用摘要 class。
public interface IAdaptable<in TIEntity, in TIDTO, TDTO>
where TDTO : TIDTO
{
void Initialize(TIEntity entity);
TDTO ToDTO();
}
public interface IAdaptable<in TIEntity, TDTO> : IAdaptable<TIEntity, TDTO, TDTO>
{
}
public abstract class AdapterBase<TEntity, TIDTO, TDTO> : IAdaptable<TEntity, TIDTO, TDTO>, TIDTO
where TDTO : TIDTO
{
protected TEntity entity;
public void Initialize(TEntity entity)
{
this.entity = entity;
}
public TDTO ToDTO()
{
return Mapper.Map<TIDTO, TDTO>(this);
}
}
此代码不起作用,因为您不能从传入的通用参数继承,即使 id 像我的父 class 一样强制执行它。
如果有人想知道为什么或这里发生了什么,这个适配器基础应用于必须实现 DTO 接口属性的适配器,然后将附加逻辑应用于 getter 和设置以防止 id 篡改和做一些基本的设置逻辑。
如果我手动将此代码应用于每个适配器,则此代码工作正常,但我更喜欢适配器基础或代理而不是适配器基础,后者将为我处理所有这些逻辑。
有谁知道我可以抽象出这个逻辑的方法,或者解决方法,这样我就不必手动将这个逻辑应用到每个适配器?
对于那些想要答案的人,我找到了一个解决方案,但你可能不喜欢它。
这是完整界面:
public interface IAdaptable<in TIEntity, in TIDTO, TDTO>
where TDTO : TIDTO
{
bool IsInitialized { get; set; }
void Initialize(TIEntity entity);
TDTO ToDTO(TIDTO iEntityDTO);
void ApplyFrom(TIDTO entityDTO);
}
现在您可以像这样创建适配器基础:
public class AdapterBase<TIEntity, TIDTO, TDTO> : IAdaptable<TIEntity, TIDTO, TDTO>
where TDTO : TIDTO
{
#region Consts
public const string FAILED_TO_INITIALIZE_ADAPTER_ERROR = "Failed to Initialize Adapter make sure you called the Initialize function";
#endregion
#region Protected Members
protected TIEntity _entity;
#endregion
#region IAdaptable
public bool IsInitialized { get; set; }
public void Initialize(TIEntity entity)
{
this._entity = entity;
IsInitialized = true;
}
public void ApplyFrom(TIDTO entityDTO)
{
if (false == IsInitialized)
{
throw new Exception(FAILED_TO_INITIALIZE_ADAPTER_ERROR);
}
Mapper.Map(entityDTO, this);
}
public TDTO ToDTO(TIDTO adaptable)
{
if (false == IsInitialized)
{
throw new Exception(FAILED_TO_INITIALIZE_ADAPTER_ERROR);
}
return Mapper.Map<TIDTO, TDTO>(adaptable);
}
#endregion
}
现在您可以像这样在通用的 crud 服务中使用您的适配器
public class AsyncCRUDService<TEntity, TIDTO, TDTO, TAdapter> : IAsyncCRUDService<TDTO>
where TDTO : TIDTO
where TEntity : class, new()
where TAdapter : class, TIDTO, IAdaptable<TEntity, TIDTO, TDTO>
{
protected DbContext _context;
protected TAdapter _adapter;
public AsyncCRUDService(DbContext context, TAdapter adapter)
{
this._context = context;
this._adapter = adapter;
}
public async virtual Task<TDTO> Get(object[] id)
{
var entity = await this._context.Set<TEntity>().FindAsync(id);
if (null == entity)
{
throw new InvalidIdException();
}
return this.AdaptToDTO(entity);
}
protected virtual TDTO AdaptToDTO(TEntity entity)
{
this._adapter.Initialize(entity);
return this._adapter.ToDTO(this._adapter);
}
}
唯一的缺点是现在您的服务依赖于硬依赖