C# 将父对象转换为子对象

C# 将父对象转换为子对象,c#,oop,C#,Oop,我有几十个域对象(用户、组、角色、社区、帖子等)。此外,我还有扩展对象(UserExt、GroupExt等),它们是从这些对象派生的,并包含一些附加数据。在我的数据访问控制层中,有一些检索基本对象的方法。当我需要用数据填充子对象时,我使用这些方法,但每次我都需要将结果转换为子类型。 因为我不能将父对象强制转换为子对象,所以我需要为每个父-子对象对提供转换器(通过构造函数、方法、现有转换器的扩展或任何其他方式)。这是我不喜欢的,好像我曾经在基类型中添加任何字段,我可能会忘记调整转换器。是否有更自动

我有几十个域对象(用户、组、角色、社区、帖子等)。此外,我还有扩展对象(UserExt、GroupExt等),它们是从这些对象派生的,并包含一些附加数据。在我的数据访问控制层中,有一些检索基本对象的方法。当我需要用数据填充子对象时,我使用这些方法,但每次我都需要将结果转换为子类型。
因为我不能将父对象强制转换为子对象,所以我需要为每个父-子对象对提供转换器(通过构造函数、方法、现有转换器的扩展或任何其他方式)。这是我不喜欢的,好像我曾经在基类型中添加任何字段,我可能会忘记调整转换器。是否有更自动化的方法从父级填充子级字段?
谢谢大家!

注:代码:

域对象:

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)
    {
        //...
    }
}

使用反射,将所有公共属性从父级复制到子级:

  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) );
      }
  }
如果在您的数据模型中,您操作并检索用户
角色
社区
发布
数据类型,那么除了“手动”实现基本对象和目标派生类之间的“转换”之外,没有其他方法

有很多方法可以做到这一点:

  • 特殊转换方法
  • 超越型铸造操作器
  • 对象映射器框架

还有更多…

只需将转换移动到父对象即可。这允许您为每个父级编写一个转换,并将属性更改保留到单个源文件

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;
    }
}
公共类父类
{
公共int Prop1{get;set;}
公共字符串Prop2{get;set;}
公共日期时间属性3{get;set;}
公共T ToChild(),其中T:Parent,new()
{
T child=新的T();
child.Prop1=this.Prop1;
child.Prop2=this.Prop2;
child.Prop3=this.Prop3;
返回儿童;
}
}

对上述示例进行小调整,以扩展方法

    /// <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);
            }
        }
    }
//
///执行从父对象到子对象的浅层转换。
/// 
/// 
/// 
///父母。
///孩子。
公共静态无效浅转换(此T父级,U子级)
{
foreach(parent.GetType().GetProperties()中的PropertyInfo属性)
{
if(property.CanWrite)
{
SetValue(子,property.GetValue(父,null),null);
}
}
}
是转换实体的最佳方式。一定要试试

顺便说一句,我扩展了@thumbmunkeys代码,如果你不想使用Automapper的话

/// <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;
    }
}
//
///封装用于将域对象映射到表示对象的有用函数。
/// 
公共静态类映射器
{
/// 
///将的对象转换为的对象。
/// 
/// 
/// 
/// 
/// 
公共静态T转换(U实例)
其中T:class,new()
其中U:class,new()
{
T instanceOfT=新的T();
PropertyInfo[]tPropertyInfos=typeof(T).GetProperties();
PropertyInfo[]uPropertyInfos=typeof(U).GetProperties();
foreach(tPropertyInfo tPropertyInfo在tPropertyInfos中)
{
foreach(uPropertyInfos.Where中的var uPropertyInfo(p=>p.Name==tPropertyInfo.Name))
{
如果(tPropertyInfo.PropertyType==uPropertyInfo.PropertyType
&&tPropertyInfo.SetMethod!=null)
{
tPropertyInfo.SetValue(instanceOfT,uPropertyInfo.GetValue(instanceOfU));
}
}
}
返回instanceOfT;
}
/// 
///将类型的实例转换为其父类型的实例:。
/// 
/// 
/// 
/// 
/// 
公共静态TParent ConvertChildToParent(TChild-child)
其中tpart:class,new()
其中TChild:class,new()
{
如果(!typeof(TChild).IsDerivedFrom(typeof(TParent)))
{
抛出新的ArgumentException(string.Format(“{0}不是从{1}.”、typeof(TChild)、typeof(TParent))、TChild派生的);
}
返回转换(子级);
}
/// 
///检查此类型是否派生自。
/// 
/// 
/// 
/// 
公共静态bool IsDerivedFrom(此类型thisType,类型parentType)
{
类型派生类型=此类型;
做
{
derivedType=derivedType.BaseType;
如果(derivedType!=null)
{
if(derivedType==parentType){return true;}
}
}while(derivedType!=null);
返回false;
}
}

你能给出一个你想做的代码示例吗?是的,有很多方法可以实现转换,但我不清楚为什么不能更隐式地填充子对象,即父对象加上一些附加功能。。。无论如何谢谢你@David B如果我从父类到子类有以下类User->Client->Supplier,那么这是一个合适的解决方案,其中每个子类对其父类只有额外的属性,并且我希望根据检索到的值使对象“更改”类。用户将(电子邮件、密码)添加到客户的(姓名、姓氏、电话、国家),供应商将添加到客户的属性(公司名称、服务类型……。@FernandoSilva它可能是。。。要记住的两个原则是:1)家长应尽量减少对儿童课程的了解。2) 每个类都应该管理自己的属性。我的想法是逐步向子类添加属性,并覆盖子类中父类的初始方法来维护“对象”。例如,属性的清理/验证、数据库检查/保存将首先在父类上配置,然后在子类中重写以适应较新的属性。
/// <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;
    }
}