我有几十个域对象(用户,组,角色,社区,帖子等)。此外,我有扩展的对象(UserExt,GroupExt等),这些对象派生自那些并包含一些附加数据。在我的数据访问控制层中,有一些检索基础对象的方法。当我需要使用数据填充子对象时,我使用这些方法,但每次我需要将结果转换为子类型
因为我不能将父对象转换为子对象,所以我需要为每个父子对提供转换器(通过构造函数,方法,现有转换器的扩展或任何其他方式)。这就是我不喜欢的,好像我曾经添加任何字段到基本类型我可能忘记调整我的转换器。是否有更多自动化方式从父母那里填充孩子的字段?
谢谢!
PS:代码:
域对象:
public class Role : OutdoorObject
{
public String Name { get; set; }
public Int32 CreatedById { get; set; }
public Int32 UpdatedById { get; set; }
}
public class RoleExt : Role
{
public IPrincipal CreatedBy { get; set; }
public IPrincipal UpdatedBy { get; set; }
}
数据访问层:
public Role GetById(Int32 roleId)
{
try
{
// seek in cache, return if found
LQ_Role lqRole = context.LQ_Roles.FirstOrDefault(r => r.RoleID == roleId);
Role result = LQMapper.LQToObject(lqRole);
// put result to cache
return result;
}
catch (Exception ex)
{
if (ex is BaseRepositoryException) throw ex;
else throw new UnknownRepositoryException(ex.Message);
}
}
服务层:
public Role GetById(IPrincipal Executer, int roleID)
{
try
{
// perform operation
Role r = _repo.GetById(roleID);
// check access
if (!CanRead(Executer, r)) throw new OperationIsNotPermittedServiceException();
return r;
}
catch (Exception ex)
{
// ...
}
}
public RoleExt GetExtById(IPrincipal Executer, int roleID)
{
try
{
// perform operation
Role r = GetById(IPrincipal Executer, int roleID);
RoleExt result = new RoleExt();
// here i need to convert r to result
// and populate addition fields
result.CreatedBy = userService.GetById(Executer, r.CreatedById);
result.UpdatedBy = userService.GetById(Executer, r.UpdatedById);
// check access
if (!CanRead(Executer, result)) throw new OperationIsNotPermittedServiceException();
return result;
}
catch (Exception ex)
{
//...
}
}
答案 0 :(得分:5)
使用反射,这会将所有公共属性从父级复制到子级:
public static void CopyOver(Parent p, Child c)
{
PropertyInfo[] props = p.GetType().GetProperties(BindingFlags.Public);
foreach( PropertyInfo pi in props)
{
pi.SetValue( c, pi.GetValue( p) );
}
}
答案 1 :(得分:1)
对上述示例进行小调整,以扩展方法...
/// <summary>
/// Performs a shallow convert from the parent to the child object.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <param name="parent">The parent.</param>
/// <param name="child">The child.</param>
public static void ShallowConvert<T, U>(this T parent, U child)
{
foreach (PropertyInfo property in parent.GetType().GetProperties())
{
if (property.CanWrite)
{
property.SetValue(child, property.GetValue(parent, null), null);
}
}
}
答案 2 :(得分:1)
如果你想要一个简单的知识来适应你所有的对象,你可以使用一个使用反射的扩展方法。
这是一个很好的例子
public static class Extension
{
public static object ToChild<TChild, TParent>(this TParent _oParent) where TChild : TParent, new()
{
PropertyInfo[] _apProperties = typeof(TParent).GetProperties();
TParent _oChild = new TChild();
foreach (PropertyInfo _piProperty in _apProperties)
{
_piProperty.SetValue(_oChild, _piProperty.GetValue(_oParent));
}
return (TChild)_oChild;
}
}
答案 3 :(得分:0)
In my data access control layer there are methods for retrieving base objects
如果您在数据模型中操作并且正在审核 User
,Group
,Role
,Community
,Post
数据类型,没有其他方法可以“手动”实现基础对象和目标派生类之间的“转换”。
有很多方法可以做到这一点:
以及更多......
答案 4 :(得分:0)
只需将转换移动到Parent对象即可。这允许您为每个父编写一个转换,并将属性更改保留到单个源文件。
public class Parent
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
public DateTime Prop3 { get; set; }
public T ToChild<T>() where T : Parent, new()
{
T child = new T();
child.Prop1 = this.Prop1;
child.Prop2 = this.Prop2;
child.Prop3 = this.Prop3;
return child;
}
}
答案 5 :(得分:0)
AutoMapper是转换实体的最佳方式。绝对试试吧。
顺便说一句,如果您不想使用Automapper,我会扩展@thumbmunkeys代码。
/// <summary>
/// Encapsulates useful functions to map domain objects with presentation objects.
/// </summary>
public static class Mapper
{
/// <summary>
/// Converts an object of <typeparamref name="U"/> to an object of <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="U"></typeparam>
/// <typeparam name="T"></typeparam>
/// <param name="instanceOfU"></param>
/// <returns></returns>
public static T Convert<U, T>(U instanceOfU)
where T : class, new()
where U : class, new()
{
T instanceOfT = new T();
PropertyInfo[] tPropertyInfos = typeof(T).GetProperties();
PropertyInfo[] uPropertyInfos = typeof(U).GetProperties();
foreach (PropertyInfo tPropertyInfo in tPropertyInfos)
{
foreach (var uPropertyInfo in uPropertyInfos.Where(p => p.Name == tPropertyInfo.Name))
{
if (tPropertyInfo.PropertyType == uPropertyInfo.PropertyType
&& tPropertyInfo.SetMethod != null)
{
tPropertyInfo.SetValue(instanceOfT, uPropertyInfo.GetValue(instanceOfU));
}
}
}
return instanceOfT;
}
/// <summary>
/// Converts an instance of type <typeparamref name="TChaild"/> to an instance of its parent type: <typeparamref name="TParent"/>.
/// </summary>
/// <typeparam name="TChild"></typeparam>
/// <typeparam name="TParent"></typeparam>
/// <param name="child"></param>
/// <returns></returns>
public static TParent ConvertChildToParent<TChild, TParent>(TChild child)
where TParent : class, new()
where TChild : class, new()
{
if (!typeof(TChild).IsDerivedFrom(typeof(TParent)))
{
throw new ArgumentException(string.Format("{0} is not derived from {1}.", typeof(TChild), typeof(TParent)), "TChild");
}
return Convert<TChild, TParent>(child);
}
/// <summary>
/// Check if this type is derived from <typeparamref name="parentType"/>.
/// </summary>
/// <param name="thisType"></param>
/// <param name="parentType"></param>
/// <returns></returns>
public static bool IsDerivedFrom(this Type thisType, Type parentType)
{
Type derivedType = thisType;
do
{
derivedType = derivedType.BaseType;
if (derivedType != null)
{
if (derivedType == parentType) { return true; }
}
} while (derivedType != null);
return false;
}
}