【问题标题】:Can you populate a derived class object using data acess methods that return base class objects?您可以使用返回基类对象的数据访问方法填充派生类对象吗?
【发布时间】:2016-01-05 09:12:56
【问题描述】:

我想创建一个实现一些新方法的继承对象。基类只是一个数据容器,并使用数据访问类填充。

我正在尝试使用强制框架,因此我更改这些基类的选项非常有限。

由于继承对象具有与基类相同的所有数据字段和访问器,我想使用基数据访问类(及其方法)来填充派生类对象。我遇到的问题是 DA 层返回 Base 类型的填充对象。

实际上我正在尝试复制字段。我知道我可以创建一个接受基础对象并有效地逐字段复制的构造函数,但这对基础表的性质来说是一场维护噩梦。

有没有什么方法可以在不重新编码 DA 层的情况下让演员“坚持”?

我认为唯一的方法是创建一个派生的数据访问类来处理派生的基类,但是有更好的方法吗?

伪代码如下。该示例可能看起来微不足道,但 DA 层封装了大量数据检查和异常处理,因此很难以任何有意义的方式进行修改而不破坏许多现有功能。

我希望它是有道理的,因为很多代码已经被丢弃了。

基类

public class oBase 
{
    #region "Constants"
    public const String FIELD_META_ID = "META_ID";
    public const String FIELD_MASTER_REF = "MASTER_REF";
    #endregion

    //Private Properties
    private Int32 m_iMetaID = 0;
    private String m_sMasterReference = "";
    //End Private Properties

    //Public Properties
    public Int32 MetaID { get { return m_iMetaID; } set { m_iMetaID = value; } }
    public String MasterReference { get { return m_sMasterReference; } set { m_sMasterReference = value; } }
    //End Public Properties
}

public class oBaseList
{
    private Int32 iMemberCount = 0;
    private List<oBase> m_BaseList = new List<oBase>();

    public Int32 Count
    {
        get { return m_BaseList.Count; }
    }

    public List<oBase> Items
    {
        get { return m_BaseList; }
    }

    public Boolean AddItem(oBase)
    {
        iMemberCount += 1;
        m_BaseList.Add(oBase);
        return true;
    }

}

扩展类

class oBaseExtended : oBase
{
    public oBaseExtended(int iMetaID)
    {
        ConnectionManagerSQL oSqlConn = new ConnectionManagerSQL();
        daBase MyConnectedData = new daBase(ref oSqlConn);

        oBase MyCastData = new oBaseExtended();
        MyCastData = MyConnectedData.GetData(iMetaID);
        oBaseExtended MyRealData = (oBaseExtended)MyCastData;
        return MyRealData;
    }

}

数据访问

public class daBase
{

    private ConnectionManagerSQL oConn;

    public daBase(ref ConnectionManagerSQL sqlConn)
    {
        oConn = sqlConn;
    }

    #region "Gets"

    public oBase GetBase(Int32 iMetaID)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append(" SELECT  ");
        sb.Append(" META_ID, ");
        sb.Append(" MASTER_REF, ");

        sb.Append(" from myTable ");
        sb.Append(" where META_ID = @META_ID");

        SqlCommand comm = new SqlCommand(sb.ToString(), oConn.DatabaseConnection);
        comm.Parameters.Add("META_ID", System.Data.SqlDbType.Int).Value = iMetaID;
        SqlDataReader drMyTableData = comm.ExecuteReader();

        return PopulateMyTableData(ref drMyTableData).Items[0];
    }
    #endregion

    #region "List population "

    private oBaseList PopulateMyTableData(ref SqlDataReader drMyTableData)
    {
        oBaseList ocdMyTableData = new oBaseList();
        oBase ocd;
        ocd = new oBase();

        ocd.MetaID = drMyTableData[oBase.FIELD_META_ID] is System.DBNull ? 0 : (Int32)drMyTableData[oBase.FIELD_META_ID];
        ocd.MasterReference = drMyTableData[oBase.FIELD_MASTER_REF] is System.DBNull ? "N/A" : (String)drMyTableData[oBase.FIELD_MASTER_REF];

        ocdMyTableData.AddItem(ocd);
        drMyTableData.Dispose();
        return ocdMyTableData;
    }

    #endregion

}

抱歉,如果这不清楚以及任何伪代码错误 - 我有点 C# 新手。

我已更新代码以更好地反映真实的底层代码。

这个问题最好是这样说的:我可以简单地使用强制转换和复制到一个继承的类型吗...

【问题讨论】:

  • 欢迎来到 Stack Overflow。如果您的示例代码格式正确并符合正常的 .NET 约定,那么它会更容易理解。它也不完整,并且做了一些似乎无关紧要的事情(例如 SQL 连接处理)。如果您发布的是真实代码而不是伪代码,那么对您的帮助会更容易
  • 注意到乔恩。但是它格式化了,但是我无法理解数据输入屏幕——实际代码跑到七页,所以更容易模拟它!
  • 这里的格式不正确 - 查看缩进。我不是要您发布您的实际代码,而是要发布一段简短但完整的真实代码,格式正确并遵循正常约定,因此我们可以轻松查看发生了什么。
  • 顺便说一句,你能给我指点一下我所践踏的约定吗——正如我所说的,我是一个 C# 新手——我的编码背景完全不同,但我对 OOP 原则很满意- 所以我的困难在于 C# 中可能/允许的内容以及一些实际语法 - 我一直使用 '' 而不是 '!='
  • msdn.microsoft.com/en-us/library/ms229045(v=vs.110).aspx 是一个很好的起点。类应该以大写字母开头,诸如“MI”之类的名称是没有意义的。 (你也不太可能在任何地方都使用ref...)

标签: c# inheritance casting


【解决方案1】:

您可以使用反射将同名属性和字段的值从一个对象复制到另一个对象。 检查https://msdn.microsoft.com/en-us/library/system.type%28v=vs.110%29.aspx 感兴趣的方法是GetPropertiesGetFields。 然后在PropertyInfoFieldInfo 中,感兴趣的方法是GetValueSetValue

您可以编写一个复制属性/字段的方法,并将其用于每个碱基/派生对。或任何其他对象对,只要同名的属性和字段是可分配的(即不能将字符串分配给 int 等)。

编辑: 此方法复制属性值:

static void CopyData(object source, object destination)
{
  Type srcType = source.GetType();
  List<PropertyInfo> destProperties = new List<PropertyInfo>(destination.GetType().GetProperties());
  foreach (PropertyInfo destProperty in destProperties)
  {
    if (destProperty.CanWrite)
    {
      PropertyInfo srcProperty = srcType.GetProperty(destProperty.Name);
      if (srcProperty != null && srcProperty.CanRead)
      {
        destProperty.SetValue(destination, srcProperty.GetValue(source));
      }
    }
  }
}

如果需要,也可以尝试添加字段复制,原理相同。

【讨论】:

  • 我也意识到了这一点,但目前反射可能超出了我的能力......你看到我的代码了吗!谢谢。
  • 给你。我添加了一个将属性复制到答案的示例。希望对您有所帮助。
【解决方案2】:

您可以通过基类构造函数填充派生类/基类共享的成员,如果需要,您还可以填充派生类中的任何扩展成员:

public class oBase
{
    private Int32 m_i = 0;
    private String m_s = "";
    public Int32 MI { get { return m_i; } set { m_i = value; } }
    public String MS { get { return m_s; } set { m_s = value; } }

    public oBase() { }

    public oBase(int i)
    {
        // populate base class members using instance of data access class
    }
}

然后,您的派生类将扩展基本构造函数以填充任何扩展属性(我认为您没有?):

public class oBaseExtended : oBase
{
    public string foo { get; set; }
    public string bar { get; set; }

    public oBaseExtended() { }

    public oBaseExtended(int i) : base(i)
    {
        // this will invoke base class contructor to populate base members

        // then populate extended members afterwards if applicable
    }
}

【讨论】:

  • 谢谢。我知道我可以做到这一点,但它最终变得很啰嗦。我最终使用了一个带有基类成员的复合类,我可以直接访问它,但这使得直接数据绑定变得困难......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-04
  • 2017-01-16
  • 2015-05-23
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多