【问题标题】:DataRow Copy Values from another DataRow with Extra ColumnDataRow 从具有额外列的另一个 DataRow 复制值
【发布时间】:2015-05-08 20:07:17
【问题描述】:

我在对应的 DataTable 中有一个像 {"Foo", "Bar"} 的 DataRow,它有 2 个字符串列。我想将这一行复制到一个新的 DataTable 中,它有 3 个字符串列,其中第 0 个是我要传入的新值。所以结果行应该看起来像 {"My", "Foo", "Bar"}。

冲洗,重复。另一个复制操作类似于 {"Bob", "Smith"} => {"My", "Bob", "Smith"}。

我尝试在 Array.Copy() 和 myDataRow.ItemArray.CopyTo(otherDataRow.ItemArray) 中使用 DataRow.ItemArray。然后我读到这不起作用,因为 ItemArray 有点只读,尽管智能感知告诉你不然。

当然我可以编写自己的循环来逐列复制值,但是.. 为什么这不是内置在库中的吗?

示例代码:

DataTable dtDestination = new DataTable();
DataTable dtSource = new DataTable();

dtSource.Columns.Add("Str1");
dtSource.Columns.Add("Str2");

dtDestination.Columns.Add("Str0");
dtDestination.Columns.Add("Str1");
dtDestination.Columns.Add("Str2");

dtSource.Rows.Add("Foo", "Bar");
dtSource.Rows.Add("Bob", "Smith");

foreach (DataRow drSrc in dtSource.Rows)
{
    DataRow drNew = dtDestination.NewRow();
    drNew["Str0"] = "My";

    //this doesn't work
    Array.Copy(drSrc.ItemArray, 0, drNew.ItemArray, 1, drSrc.ItemArray.Length);

    //this doesn't work either
    drSrc.ItemArray.CopyTo(drNew.ItemArray, 1);

    //I want to add the "new row" to my destination table,
    //*WITH* the contents from the source-row plus the "My" value in the 0th column!
    dtDestination.Rows.Add(drNew);
}

【问题讨论】:

  • 迭代有什么问题? drNew[1] = drSrc[0]; drNew[2] = drSrc[1]
  • 这就是我的意思...我可以通过循环轻松做到这一点,很好。我在问为什么这种东西没有内置到框架中,或者至少没有内置到某个可以调用的库中。
  • 因为它简单易行。例如,将比数组复制执行得更好。
  • @Zer0 如何表现更好?它仍然是 O(N),其中 N = 数组大小 = 行中的列数。但我确实明白你的意思,实现自己很简单——没有DataRow.CopyValuesFrom(otherDataRow, startingIndex) 或其他东西似乎很愚蠢。
  • 因为在您调用NewRow 时已经创建了ItemArray。它增加了内存压力,为 GC 产生了更多垃圾。接受的答案是每行创建 2 个数组。至于您的示例,如果我想复制第 1、2 和 4 列怎么办?这是一个太具体的用例,迭代非常简单。这里没有真正需要解决的问题。

标签: c# datarow


【解决方案1】:

你不能在没有 SetValue 的情况下设置 .ItemArray 值 但是你可以设置 ItemArray 本身

        DataTable dtDestination = new DataTable();
        DataTable dtSource = new DataTable();

        dtSource.Columns.Add("Str1");
        dtSource.Columns.Add("Str2");

        dtDestination.Columns.Add("Str0");
        dtDestination.Columns.Add("Str1");
        dtDestination.Columns.Add("Str2");

        dtSource.Rows.Add("Foo", "Bar");
        dtSource.Rows.Add("Bob", "Smith");

        foreach (DataRow drSrc in dtSource.Rows)
        {
            DataRow drNew = dtDestination.NewRow();
            var array = new object[drSrc.ItemArray.Length];
            array[0] = "My";
            Array.Copy(drSrc.ItemArray, 0, array, 1, drSrc.ItemArray.Length);
            drNew.ItemArray = array;
            dtDestination.Rows.Add(drNew);
        }

您应该将测试值添加到源表,而不是目标表...

【讨论】:

  • 不错的答案!感谢您将测试值放入 dtDestination;我已经编辑了我的问题,将它们放在 dtSource 中。
【解决方案2】:

创建扩展方法:

public static void CopyValuesFrom(this DataRow me, DataRow copyFrom, int insertIndex = 0, int copyIndex = 0, int count = 0)
{
    if (count == 0)
        count = Math.Min(copyFrom.ItemArray.Length - copyIndex, me.ItemArray.Length - insertIndex);
    for (var i = 0; i < count; i++)
        me[insertIndex + i] = copyFrom[copyIndex + i];
}

复制:

drNew.CopyValuesFrom(drSrc, 1);

【讨论】:

  • 我写了一个迷你库(虽然我可能误用了这个词),如果你想查看我的代码,请告诉我你的想法 -- dotnetfiddle.net/Widget/AGswyE
  • @NateJ - 这与我的答案相似,但不太灵活。一些事情。它们不是扩展方法,您不能指定自己的要复制的计数。就个人而言,如果您想仔细检查输入,我会抛出更具体的异常(如InvalidOperationException)。在这种情况下,我还会检查 null 并抛出 ArgumentNullException
【解决方案3】:

有一种简单的方法可以做到这一点,只需使用 ImportRow 方法并在附加列的此供应值之后额外使用

【讨论】:

    猜你喜欢
    • 2016-05-26
    • 1970-01-01
    • 2016-12-05
    • 2012-02-06
    • 1970-01-01
    • 2014-11-10
    • 1970-01-01
    • 2012-08-26
    • 1970-01-01
    相关资源
    最近更新 更多