C# MemberwiseClone: Shallow Copy Basics
Learn how C# MemberwiseClone creates shallow copies, why nested objects are shared, and when a deep copy is necessary.
MemberwiseClone is a protected method on System.Object that creates a shallow copy of the current object. It copies value-type fields by value and reference-type fields by reference, so the new object shares nested objects with the original. This article covers how MemberwiseClone behaves, how to expose it, and when a deep copy is necessary.
MemberwiseClone is often the simplest way to clone an object without writing manual field-by-field copying, but its behavior is frequently misunderstood around reference types and nested objects.
How MemberwiseClone Works
MemberwiseClone is a native method in the CLR. It allocates a new object of the same runtime type and copies all non-static fields from the original object to the new one. For value-type fields, the values are copied directly. For reference-type fields, only the reference is copied, meaning the new object points to the same instance as the original.
Because the method is protected, you cannot call it directly from arbitrary code outside the class hierarchy. Instead, you typically expose it through a public method or by implementing the ICloneable interface.
public class Person { public string Name { get; set; } public Address HomeAddress { get; set; } public Person ShallowCopy() => (Person)MemberwiseClone(); } public class Address { public string Street { get; set; } public string City { get; set; } }
In the example above, calling ShallowCopy() on a Person instance creates a new Person whose Name string and HomeAddress reference are the same as the original. The HomeAddress object itself is not duplicated.
Shallow Copy vs Deep Copy
A shallow copy duplicates the top-level object but shares references to any reference-type fields. A deep copy duplicates the entire object graph, including all nested objects. The distinction is critical when the object contains mutable reference types.
Consider this scenario:
var original = new Person { Name = "Alice", HomeAddress = new Address { Street = "123 Main St", City = "Springfield" } }; var shallow = original.ShallowCopy(); shallow.HomeAddress.City = "Shelbyville"; Console.WriteLine(original.HomeAddress.City); // Output: Shelbyville
Because HomeAddress is shared, modifying the copy's address also affects the original. A deep copy would create a new Address instance, isolating the two objects.
Implementing ICloneable with MemberwiseClone
The ICloneable interface requires a Clone() method that returns an object. Many developers use MemberwiseClone as a quick implementation, but this can be misleading if the class contains reference types. The interface does not specify whether the clone should be shallow or deep, so you must document the behavior.
public class Person : ICloneable { public string Name { get; set; } public Address HomeAddress { get; set; } public object Clone() => MemberwiseClone(); }
This implementation provides a shallow copy. If you need a deep copy, you must manually clone reference-type fields:
public object Clone() { var clone = (Person)MemberwiseClone(); clone.HomeAddress = new Address { Street = HomeAddress.Street, City = HomeAddress.City }; return clone; }
Be aware that MemberwiseClone does not call any constructors, so initialization logic in constructors and field initializers is skipped. This can be an advantage for performance but a pitfall if the object relies on constructor behavior.
When to Use MemberwiseClone
Use MemberwiseClone when you need a fast, simple shallow copy and you understand that reference types are shared. Common use cases include:
- Implementing value-object-like classes where fields are immutable or where sharing references is acceptable.
- Creating a prototype pattern where the copy is intended to be a starting point and you manually handle nested objects.
- Copying objects that contain only value types or immutable strings, making shallow and deep copies effectively identical.
Avoid MemberwiseClone when the object graph contains mutable reference types and you need isolation. In such cases, a deep copy is necessary, and MemberwiseClone alone is insufficient.
Performance and Memory Considerations
MemberwiseClone is often faster than a manual field-by-field copy because the CLR copies all fields directly instead of requiring per-field assignment code. The exact performance difference depends on the object size and the cost of the alternative implementation.
Memory usage is another factor. A shallow copy allocates memory for the new top-level object but does not allocate additional memory for referenced objects. This can be memory-efficient when sharing is acceptable, but it also means changes to nested objects propagate across all copies.
If you need deep copies, the cost increases because you must recursively clone every reference type. In that case, consider serialization-based approaches or manual cloning, depending on the complexity of the object graph.
Common Pitfalls and Limitations
One common mistake is assuming MemberwiseClone creates a deep copy. It does not, and this misunderstanding leads to subtle bugs when nested objects are modified. Another pitfall is exposing MemberwiseClone without documenting its shallow behavior, especially when implementing ICloneable.
The method is protected, so it can be called from the declaring class or derived classes, but not from arbitrary code outside that hierarchy. To expose cloning to callers, you typically wrap it in a public method, which is good practice but adds a small layer of indirection.
MemberwiseClone also copies fields regardless of their accessibility, including private fields. A readonly field is copied like any other field; the clone is still subject to C#'s readonly rules, so the field itself cannot be reassigned in ordinary code. If the field is a mutable reference type, however, the clone and original still share the same object, so mutating that object affects both instances.
Finally, MemberwiseClone is not virtual, so you cannot override it in derived classes to customize cloning behavior. If a derived class adds reference-type fields, a base class implementation of MemberwiseClone still copies those fields; the derived class may need to expose its own cloning method if it requires a more specific return type or extra logic. MemberwiseClone copies the fields of the runtime type, so it works correctly even when invoked through a base class method, but you lose the ability to inject custom logic through overriding.
Understanding these limitations helps you decide when MemberwiseClone is appropriate and when a more explicit cloning strategy is required.