【问题标题】:Does SqlCommand.Clone() create a deep copy or shallow copy?SqlCommand.Clone() 是创建深拷贝还是浅拷贝?
【发布时间】:2011-10-13 02:36:17
【问题描述】:

SqlCommand.Clone() 是创建深拷贝还是浅拷贝?另外,从多个线程并发调用Clone()是否安全(创建一个多个线程可以复制、设置参数值和执行的命令)?

【问题讨论】:

  • 有关克隆、深拷贝和浅拷贝以及示例的更多信息,请参阅Object.MemberwiseClone 方法stackoverflow.com/questions/699210/…
  • 我的问题的原因是它是否是同时来自多个线程的 Clone() SqlCommand 线程安全的。从讨论来看,这似乎是正确的,因此即使它不是深度克隆,它也确实克隆了参数集。因此,在启动时,您可以准备一次 SqlCommand,然后从多个并行线程中克隆它以节省一些工作。

标签: .net clone sqlcommand


【解决方案1】:

从多个线程调用Clone 是不安全的,因为SqlCommand 类本身不是线程安全类。你应该在克隆之前lock..

但是您可以使用Reflector 之类的程序查看SqlCommand.Clone() 方法,这里是实际代码:

public SqlCommand Clone()
{
    SqlCommand command = new SqlCommand(this);
    Bid.Trace("<sc.SqlCommand.Clone|API> %d#, clone=%d#\n", this.ObjectID, command.ObjectID);
    return command;
}

internal static void Trace(string fmtPrintfW, int a1, int a2)
{
    if (((modFlags & ApiGroup.Trace) != ApiGroup.Off) && (modID != NoData))
    {
        NativeMethods.Trace(modID, UIntPtr.Zero, UIntPtr.Zero, fmtPrintfW, a1, a2);
    }
}

[DllImport("System.Data.dll", EntryPoint="DllBidTraceCW", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Unicode)]
internal static extern void Trace(IntPtr hID, UIntPtr src, UIntPtr info, string fmtPrintfW, int a1, int a2);

private SqlCommand(SqlCommand from) : this()
{
    this.CommandText = from.CommandText;
    this.CommandTimeout = from.CommandTimeout;
    this.CommandType = from.CommandType;
    this.Connection = from.Connection;
    this.DesignTimeVisible = from.DesignTimeVisible;
    this.Transaction = from.Transaction;
    this.UpdatedRowSource = from.UpdatedRowSource;
    SqlParameterCollection parameters = this.Parameters;
    foreach (object obj2 in from.Parameters)
    {
        parameters.Add((obj2 is ICloneable) ? (obj2 as ICloneable).Clone() : obj2);
    }
}

您可以看到它创建了一个新实例并将旧实例的所有属性添加到其中,但它不会深度复制所有属性“例如Connection”,因此它是浅拷贝。

【讨论】:

  • 我不希望它克隆像 SqlConnection 这样的关键资源。我会说,因为它克隆了所有 ICloneable 参数,因此它在深层副本中执行了“最佳尝试”。在我正在审查的应用程序中,它从不使用“原始”SqlCommand,因此“来自”或“原始”实例的连接和事务属性将始终为空。
  • @yzorg:是的,但是因为它不会像SqlConnectionParameters..那样深度克隆所有数据,所以它被认为是浅拷贝。如果它深度复制所有数据,它只会考虑deep copy,因此如果您更改原始或副本的任何属性,无论如何它都不会影响另一个。
【解决方案2】:

SqlCommand.Clone 方法执行浅拷贝。任何作为引用类型的属性都将在两个 SqlCommand 实例中表示相同的对象。所以,不是线程安全的。

AFAIK,.NET 框架中的所有 Clone() (MemberwiseClone) 方法都是浅拷贝。

您尚未发布您的代码,但我建议您创建一个新的 SqlCommand 而不是克隆。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2013-08-23
    相关资源
    最近更新 更多