SqlCommand.Clone() 是创建深拷贝还是浅拷贝?

Posted

技术标签:

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

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

【问题讨论】:

有关克隆、深拷贝和浅拷贝以及示例的更多信息,请参阅Object.MemberwiseClone 方法***.com/questions/699210/… 我的问题的原因是它是否是同时来自多个线程的 Clone() SqlCommand 线程安全的。从讨论来看,这似乎是正确的,因此即使它不是深度克隆,它也确实克隆了参数集。因此,在启动时,您可以准备一次 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 而不是克隆。

【讨论】:

以上是关于SqlCommand.Clone() 是创建深拷贝还是浅拷贝?的主要内容,如果未能解决你的问题,请参考以下文章

Java深拷贝和浅拷贝(深克隆和浅克隆)

对象浅拷贝和深拷贝有什么区别

对象浅拷贝和深拷贝有什么区别

React 是在内部创建 prevState 的深拷贝还是浅拷贝?

深拷贝(什么是深拷贝,为什么要进行深拷贝,如何进行深拷贝(至少写三种方法,手写深拷贝))

浅拷贝深拷贝