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

7
< p >SqlCommand.Clone() 方法创建深层拷贝还是浅层拷贝?此外,同时从多个线程调用 Clone() 方法是否安全(创建一个命令,多个线程可以复制、设置参数值和执行)?

有关克隆、深拷贝与浅拷贝以及示例的更多信息,请参阅 Object.MemberwiseClone 方法。https://dev59.com/l3RB5IYBdhLWcg3wLUq3#4186747 - Sreekumar P
我的问题是关于在多个线程同时从Clone() SqlCommand是否线程安全。从讨论中得出结论,即使它不是深度克隆,它也会克隆参数集。因此,在启动时,您可以准备一次SqlCommand,然后稍后在许多线程中并行克隆它以节省一些工作。 - yzorg
2个回答

3

在多个线程中调用 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,因此“from”或“original”实例上的Connection和Transaction属性将始终为空。 - yzorg
@yzorg:没错,但由于它不像“SqlConnection”、“Parameters”那样深度克隆所有数据,因此被认为是浅拷贝。只有当它深度复制所有数据时才被视为“深拷贝”,因此如果您更改原始或副本的任何属性,则不会以任何方式影响另一个。 - Jalal Said

2
SqlCommand.Clone 方法执行浅层复制。任何引用类型的属性在两个 SqlCommand 实例中表示相同的对象。因此,不是线程安全的。
据我所知,.NET Framework 中所有的 Clone()(MemberwiseClone)方法都是浅层复制。
你没有发布你的代码,但我建议创建一个新的 SqlCommand 而不是克隆它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接