![]() |
VOOZH | about |
dotnet add package ktsu.DeepClone --version 2.0.11
NuGet\Install-Package ktsu.DeepClone -Version 2.0.11
<PackageReference Include="ktsu.DeepClone" Version="2.0.11" />
<PackageVersion Include="ktsu.DeepClone" Version="2.0.11" />Directory.Packages.props
<PackageReference Include="ktsu.DeepClone" />Project file
paket add ktsu.DeepClone --version 2.0.11
#r "nuget: ktsu.DeepClone, 2.0.11"
#:package ktsu.DeepClone@2.0.11
#addin nuget:?package=ktsu.DeepClone&version=2.0.11Install as a Cake Addin
#tool nuget:?package=ktsu.DeepClone&version=2.0.11Install as a Cake Tool
A lightweight .NET library providing a simple, generic interface for implementing deep cloning functionality in your classes.
👁 License
👁 NuGet
👁 NuGet Downloads
👁 Build Status
👁 GitHub Stars
The ktsu.DeepClone library defines the IDeepCloneable interface, which allows you to create deep copies of objects. The DeepCloneable<TDerived> base class implements this interface while providing type-safe cloning. This is particularly useful in scenarios where you need to duplicate an object while ensuring that its references to other objects are also fully cloned, not just copied.
Inspired by and based on the ppy/osu! project's cloning utilities, this library is licensed under the MIT License.
class)Install-Package ktsu.DeepClone
dotnet add package ktsu.DeepClone
<PackageReference Include="ktsu.DeepClone" Version="x.y.z" />
using ktsu.DeepClone;
public class MyClass : DeepCloneable<MyClass>
{
public int Value { get; set; }
public MyClass? NestedObject { get; set; }
protected override MyClass CreateInstance() => new MyClass();
protected override void DeepClone(MyClass clone)
{
ArgumentNullException.ThrowIfNull(clone);
base.DeepClone(clone);
clone.Value = this.Value;
clone.NestedObject = this.NestedObject?.DeepClone();
}
}
You can then create deep copies of your objects:
var original = new MyClass
{
Value = 42,
NestedObject = new MyClass { Value = 84 }
};
var copy = original.DeepClone();
// The copy is a completely independent object
copy.Value = 100;
copy.NestedObject.Value = 200;
// Original remains unchanged
Console.WriteLine(original.Value); // Outputs: 42
Console.WriteLine(original.NestedObject.Value); // Outputs: 84
The library provides a non-generic interface for deep cloning:
// Non-generic interface - Allows polymorphic cloning that returns object
public interface IDeepCloneable
{
object DeepClone();
}
The DeepCloneable<TDerived> base class implements this interface while providing type-safe cloning through its generic implementation. This allows classes that inherit from it to have strongly-typed DeepClone() methods that return their specific type, while still supporting polymorphic cloning through the IDeepCloneable interface.
For simpler implementation, you can use the provided DeepCloneable<TDerived> abstract class which implements the non-generic IDeepCloneable interface:
public class Person : DeepCloneable<Person>
{
public string? Name { get; set; }
public int Age { get; set; }
public List<string> Interests { get; set; } = new();
// Required: Create a new instance
protected override Person CreateInstance() => new Person();
// Required: Copy your properties
protected override void DeepClone(Person clone)
{
ArgumentNullException.ThrowIfNull(clone);
clone.Name = Name;
clone.Age = Age;
// For collections, use the DeepCloneFrom extension method
// This handles cloning of all elements in the collection
clone.Interests.DeepCloneFrom(Interests);
}
}
The library uses a C# implementation of the Curiously Recurring Template Pattern (CRTP) to provide type safety in inheritance hierarchies. This pattern allows derived classes to receive their actual concrete type in the DeepClone method without any casting.
// The generic type parameter TDerived is the derived class itself
public abstract class DeepCloneable<TDerived> : IDeepCloneable
where TDerived : DeepCloneable<TDerived>
{
// Public method that creates and returns a strongly typed clone
public TDerived DeepClone()
{
// Create a new instance of the derived type using an abstract factory method
TDerived clone = CreateInstance();
// Call protected method to copy properties
DeepClone(clone);
return clone;
}
// Implementation of the non-generic interface
object IDeepCloneable.DeepClone() => DeepClone();
// To be implemented by derived classes to create instances of themselves
protected abstract TDerived CreateInstance();
// To be implemented by derived classes to copy properties
protected virtual void DeepClone(TDerived clone) { }
}
With this pattern:
DeepClone() method returns the exact type of the derived classDeepClone(TDerived clone) method receives a parameter of the derived type, not the base typeThis ensures complete type safety throughout the inheritance chain.
When implementing deep cloning in a class hierarchy, it's critical to call base.DeepClone() first in derived classes:
// Base class
public abstract class Shape<T> : DeepCloneable<T> where T : Shape<T>
{
public int Id { get; set; }
public string? Name { get; set; }
public List<string> Tags { get; set; } = new();
protected override void DeepClone(T clone)
{
ArgumentNullException.ThrowIfNull(clone);
// Clone base class properties
clone.Id = Id;
clone.Name = Name;
// Use DeepCloneFrom for collections
clone.Tags.DeepCloneFrom(Tags);
}
}
// Derived class
public class Circle : Shape<Circle>
{
public double Radius { get; set; }
public Dictionary<string, double> Measurements { get; set; } = new();
protected override Circle CreateInstance() => new Circle();
protected override void DeepClone(Circle clone)
{
// IMPORTANT: Always call base.DeepClone first to clone base properties
base.DeepClone(clone);
// Then clone properties specific to this type
clone.Radius = Radius;
// Use DeepCloneFrom for collections
clone.Measurements.DeepCloneFrom(Measurements);
}
}
// Further derived class
public class ColoredCircle : Circle
{
public string? Color { get; set; }
public HashSet<string> ColorGradients { get; set; } = new();
protected override ColoredCircle CreateInstance() => new ColoredCircle();
protected override void DeepClone(ColoredCircle clone)
{
// Call base first to handle Circle and Shape properties
base.DeepClone(clone);
// Then clone ColoredCircle specific properties
clone.Color = Color;
// Use DeepCloneFrom for collections
clone.ColorGradients.DeepCloneFrom(ColorGradients);
}
}
Note that each derived class's DeepClone() method receives a parameter of its own type:
Shape<T>.DeepClone(T clone) receives a TCircle.DeepClone(Circle clone) receives a CircleColoredCircle.DeepClone(ColoredCircle clone) receives a ColoredCircleThis is achieved through the CRTP pattern and means that no casting is needed in any of these methods.
Usage:
var original = new ColoredCircle
{
Id = 1,
Name = "My Circle",
Tags = { "round", "geometric" },
Radius = 10.5,
Measurements = { ["diameter"] = 21.0 },
Color = "Blue",
ColorGradients = { "lightblue", "darkblue" }
};
var clone = original.DeepClone();
// All properties from the entire hierarchy are cloned
Console.WriteLine(clone.Id); // 1
Console.WriteLine(clone.Name); // My Circle
Console.WriteLine(clone.Tags[0]); // round
Console.WriteLine(clone.Radius); // 10.5
Console.WriteLine(clone.Color); // Blue
When working with inheritance hierarchies that have multiple derived types from a common ancestor, you need to carefully implement deep cloning to maintain polymorphism. This is especially important when dealing with collections of different derived types.
The recommended approach is to use the CRTP pattern throughout the inheritance hierarchy along with interface hierarchies for polymorphism:
// Non-generic interface for all animals to enable polymorphism
public interface IAnimal
{
string? Name { get; set; }
int Age { get; set; }
}
// Base class in the hierarchy using CRTP pattern
public abstract class Animal<TDerived> : DeepCloneable<TDerived>, IAnimal
where TDerived : Animal<TDerived>
{
public string? Name { get; set; }
public int Age { get; set; }
protected override void DeepClone(TDerived clone)
{
ArgumentNullException.ThrowIfNull(clone);
base.DeepClone(clone);
clone.Name = Name;
clone.Age = Age;
}
}
// Interface for mammals, extending the animal interface
public interface IMammal : IAnimal
{
int NumberOfLegs { get; set; }
string? FurColor { get; set; }
}
// Intermediate class for mammals, continuing the CRTP pattern
public abstract class Mammal<TDerived> : Animal<TDerived>, IMammal
where TDerived : Mammal<TDerived>
{
public int NumberOfLegs { get; set; }
public string? FurColor { get; set; }
protected override void DeepClone(TDerived clone)
{
ArgumentNullException.ThrowIfNull(clone);
base.DeepClone(clone);
clone.NumberOfLegs = NumberOfLegs;
clone.FurColor = FurColor;
}
}
// Interface for dogs
public interface IDog : IMammal
{
string? Breed { get; set; }
bool IsTrained { get; set; }
}
// Concrete implementation - Dog
public class Dog : Mammal<Dog>, IDog
{
public string? Breed { get; set; }
public bool IsTrained { get; set; }
protected override Dog CreateInstance() => new Dog();
protected override void DeepClone(Dog clone)
{
ArgumentNullException.ThrowIfNull(clone);
base.DeepClone(clone);
clone.Breed = Breed;
clone.IsTrained = IsTrained;
}
}
// Interface for cats
public interface ICat : IMammal
{
bool IsIndoor { get; set; }
string? FavoriteToy { get; set; }
}
// Another concrete implementation - Cat
public class Cat : Mammal<Cat>, ICat
{
public bool IsIndoor { get; set; }
public string? FavoriteToy { get; set; }
protected override Cat CreateInstance() => new Cat();
protected override void DeepClone(Cat clone)
{
ArgumentNullException.ThrowIfNull(clone);
base.DeepClone(clone);
clone.IsIndoor = IsIndoor;
clone.FavoriteToy = FavoriteToy;
}
}
// Container for a collection of polymorphic animals using the common interface
public class AnimalShelter : DeepCloneable<AnimalShelter>
{
// Collection of animals using the common interface for polymorphism
public Collection<IAnimal> Animals { get; } = [];
protected override AnimalShelter CreateInstance() => new AnimalShelter();
protected override void DeepClone(AnimalShelter clone)
{
ArgumentNullException.ThrowIfNull(clone);
base.DeepClone(clone);
clone.Animals.DeepCloneFrom(Animals);
}
}
With this approach:
Usage example with different animal types:
// Create animals
var dog = new Dog
{
Name = "Buddy",
Age = 3,
NumberOfLegs = 4,
FurColor = "Golden",
Breed = "Labrador",
IsTrained = true
};
var cat = new Cat
{
Name = "Whiskers",
Age = 2,
NumberOfLegs = 4,
FurColor = "Tabby",
IsIndoor = true,
FavoriteToy = "Mouse"
};
// Create the shelter and add animals through the common interface
var shelter = new AnimalShelter();
shelter.Animals.Add(dog); // Adding a Dog as IAnimal
shelter.Animals.Add(cat); // Adding a Cat as IAnimal
// Deep clone the shelter and all its animals
var clonedShelter = shelter.DeepClone();
// The cloned animals maintain their concrete types through the interfaces
var clonedDog = clonedShelter.Animals[0] as Dog; // Type checking with 'as'
var clonedCat = clonedShelter.Animals[1] as Cat;
// Access specific derived type properties
Console.WriteLine(clonedDog?.Breed); // "Labrador"
Console.WriteLine(clonedCat?.FavoriteToy); // "Mouse"
// Modifying the clone doesn't affect the original
clonedDog!.Breed = "Golden Retriever";
clonedCat!.FavoriteToy = "Ball";
Console.WriteLine(dog.Breed); // Still "Labrador"
Console.WriteLine(cat.FavoriteToy); // Still "Mouse"
Immutable collections require special handling. The library provides extension methods for common immutable collection types:
public class DocumentWithImmutables : DeepCloneable<DocumentWithImmutables>
{
public string? Title { get; set; }
public ImmutableArray<string> Keywords { get; set; }
public ImmutableList<Reference> References { get; set; }
public ImmutableDictionary<string, Author> Authors { get; set; }
protected override DocumentWithImmutables CreateInstance() => new DocumentWithImmutables();
protected override void DeepClone(DocumentWithImmutables clone)
{
ArgumentNullException.ThrowIfNull(clone);
clone.Title = Title;
// For immutable collections of value types, direct assignment is fine
clone.Keywords = Keywords;
// For immutable collections of reference types, use DeepClone extension method
clone.References = References.DeepClone();
clone.Authors = Authors.DeepClone();
}
}
public class Reference : DeepCloneable<Reference>
{
public string? Citation { get; set; }
public int Year { get; set; }
protected override Reference CreateInstance() => new Reference();
protected override void DeepClone(Reference clone)
{
ArgumentNullException.ThrowIfNull(clone);
clone.Citation = Citation;
clone.Year = Year;
}
}
public class Author : DeepCloneable<Author>
{
public string? Name { get; set; }
protected override Author CreateInstance() => new Author();
protected override void DeepClone(Author clone)
{
ArgumentNullException.ThrowIfNull(clone);
clone.Name = Name;
}
}
public class ComplexObject : DeepCloneable<ComplexObject>
{
public string? Name { get; set; }
public List<ItemObject> Items { get; set; } = new();
public Dictionary<string, DataObject> DataMapping { get; set; } = new();
public HashSet<int> UniqueIds { get; set; } = new();
protected override ComplexObject CreateInstance() => new ComplexObject();
protected override void DeepClone(ComplexObject clone)
{
ArgumentNullException.ThrowIfNull(clone);
clone.Name = Name;
// Use DeepCloneFrom for all collections - this handles cloning correctly
clone.Items.DeepCloneFrom(Items);
clone.DataMapping.DeepCloneFrom(DataMapping);
// Even for value type collections, DeepCloneFrom can be used for consistency
// This is equivalent to copying each element manually
clone.UniqueIds.DeepCloneFrom(UniqueIds);
}
}
public class ItemObject : DeepCloneable<ItemObject>
{
public int Id { get; set; }
public string? Description { get; set; }
protected override ItemObject CreateInstance() => new ItemObject();
protected override void DeepClone(ItemObject clone)
{
ArgumentNullException.ThrowIfNull(clone);
clone.Id = Id;
clone.Description = Description;
}
}
public class DataObject : DeepCloneable<DataObject>
{
public byte[]? Data { get; set; }
protected override DataObject CreateInstance() => new DataObject();
protected override void DeepClone(DataObject clone)
{
ArgumentNullException.ThrowIfNull(clone);
// For arrays, create a new copy
clone.Data = Data?.ToArray();
}
}
IDeepCloneable InterfaceThe non-generic interface for implementing deep cloning functionality.
| Name | Return Type | Description |
|---|---|---|
DeepClone() |
object |
Creates a deep copy of the object, returned as an object that can be cast to the appropriate type |
DeepCloneable<TDerived> Abstract ClassBase class that simplifies implementing deep cloning functionality and implements IDeepCloneable while providing strongly-typed cloning.
| Name | Return Type | Description |
|---|---|---|
CreateInstance() |
TDerived |
Creates a new instance of the derived type |
DeepClone(TDerived clone) |
void |
Copies all properties and fields from the current instance to the clone |
Extension methods for deep cloning various container types.
| Name | Container Type | Description |
|---|---|---|
DeepClone<T> |
IEnumerable<T?>? |
Creates a deep clone of an enumerable collection |
DeepClone<TKey, TValue> |
IDictionary<TKey, TValue?>? |
Creates a deep clone of a dictionary |
DeepClone<TKey, TValue> |
IReadOnlyDictionary<TKey, TValue?>? |
Creates a deep clone of a read-only dictionary |
DeepClone<T> |
HashSet<T?>? |
Creates a deep clone of a hash set, preserving the comparer |
DeepClone<T> |
SortedSet<T?>? |
Creates a deep clone of a sorted set, preserving the comparer |
DeepClone<T> |
Stack<T?>? |
Creates a deep clone of a stack, preserving the element order |
DeepClone<T> |
ImmutableArray<T> |
Creates a deep clone of an immutable array |
DeepClone<T> |
ImmutableList<T> |
Creates a deep clone of an immutable list |
DeepClone<TKey, TValue> |
ImmutableDictionary<TKey, TValue> |
Creates a deep clone of an immutable dictionary |
DeepClone<TKey, TValue> |
ImmutableSortedDictionary<TKey, TValue> |
Creates a deep clone of an immutable sorted dictionary |
DeepClone<T> |
ImmutableHashSet<T> |
Creates a deep clone of an immutable hash set |
DeepClone<T> |
ImmutableSortedSet<T> |
Creates a deep clone of an immutable sorted set |
DeepClone<T> |
ImmutableStack<T> |
Creates a deep clone of an immutable stack |
DeepClone<T> |
ImmutableQueue<T> |
Creates a deep clone of an immutable queue |
Convenience methods for cloning elements directly into an existing collection.
| Name | Collection Types | Description |
|---|---|---|
DeepCloneFrom<T> |
ICollection<T> |
Clones all elements from source collection into the target collection |
DeepCloneFrom<TKey, TValue> |
IDictionary<TKey, TValue> |
Clones all key-value pairs from source dictionary into the target dictionary |
DeepCloneFrom<T> |
ISet<T> |
Clones all elements from source set into the target set |
Usage Example:
// For collections of IDeepCloneable objects
targetList.DeepCloneFrom(sourceList);
targetDictionary.DeepCloneFrom(sourceDictionary);
targetSet.DeepCloneFrom(sourceSet);
// This is equivalent to (but more concise than):
foreach (var item in sourceList)
{
targetList.Add(item.DeepClone());
}
When implementing DeepClone in derived classes, it's critical to call base.DeepClone(clone) first to ensure proper cloning of base class properties. This pattern creates a chain of calls that ensures all properties throughout the inheritance hierarchy are properly cloned.
protected override void DeepClone(MyDerivedClass clone)
{
// ALWAYS call base.DeepClone first
base.DeepClone(clone);
// Then clone derived class properties
clone.DerivedProperty1 = DerivedProperty1;
clone.DerivedProperty2 = DerivedProperty2?.DeepClone();
// Use DeepCloneFrom for collections
clone.DerivedCollection.DeepCloneFrom(DerivedCollection);
}
Benefits of this approach:
When implementing deep cloning, follow these guidelines:
DeepClone() method (with null check)DeepCloneFrom extension methodsbase.DeepClone(clone) first in derived classesArgumentNullException.ThrowIfNull or null conditionalsDeep cloning can be a resource-intensive operation, especially for complex object graphs. Here are some tips to optimize performance:
Example of optimized cloning for a large object:
public class OptimizedObject : DeepCloneable<OptimizedObject>
{
// Expensive to clone, but rarely modified
private ExpensiveResource? _resource;
private ExpensiveResource? _clonedResource;
public ExpensiveResource? Resource
{
get => _resource;
set
{
_resource = value;
_clonedResource = null; // Invalidate cached clone
}
}
protected override OptimizedObject CreateInstance() => new OptimizedObject();
protected override void DeepClone(OptimizedObject clone)
{
ArgumentNullException.ThrowIfNull(clone);
// Lazy clone the expensive resource only when needed
if (_resource != null)
{
// Cache the cloned resource to avoid redundant deep cloning
_clonedResource ??= _resource.DeepClone();
clone._resource = _clonedResource;
}
}
}
Symptom: Changes to a cloned object affect the original object.
Solution: Ensure all reference-type properties are being properly deep cloned. Check for:
Symptom: StackOverflowException occurs during deep cloning.
Solution: This typically indicates a circular reference issue:
public class NodeWithCircularReferences : DeepCloneable<NodeWithCircularReferences>
{
public string? Name { get; set; }
public NodeWithCircularReferences? Parent { get; set; }
public List<NodeWithCircularReferences> Children { get; set; } = new();
// Dictionary for tracking already cloned instances across the object graph
private static readonly ThreadLocal<Dictionary<NodeWithCircularReferences, NodeWithCircularReferences>> CloneTracker =
new(() => new Dictionary<NodeWithCircularReferences, NodeWithCircularReferences>());
protected override NodeWithCircularReferences CreateInstance() => new();
protected override void DeepClone(NodeWithCircularReferences clone)
{
ArgumentNullException.ThrowIfNull(clone);
base.DeepClone(clone);
// Ensure we have a clone tracker
var cloneTracker = CloneTracker.Value!;
// Track this instance and its clone
cloneTracker[this] = clone;
// Set simple properties
clone.Name = Name;
// Handle potential circular reference with Parent
if (Parent != null)
{
// Check if parent was already cloned in this cloning operation
if (cloneTracker.TryGetValue(Parent, out var parentClone))
clone.Parent = parentClone;
else
clone.Parent = Parent.DeepClone(); // This will add to the tracker
}
// Handle collection of children that might have circular references
foreach (var child in Children)
{
// Check if child was already cloned in this operation
if (cloneTracker.TryGetValue(child, out var childClone))
clone.Children.Add(childClone);
else
clone.Children.Add(child.DeepClone()); // This will add to the tracker
}
}
}
Symptom: After cloning a polymorphic collection, objects don't maintain their derived types.
Solution: Ensure you're implementing IDeepCloneable correctly for polymorphic use:
Symptom: Immutable collections don't clone properly or reference equality is maintained.
Solution: Use the appropriate extension methods specific to immutable collections:
Contributions are welcome! Here's how you can help:
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)Please make sure to update tests as appropriate and adhere to the existing coding style.
This project is licensed under the MIT License - see the file for details.
This library is inspired by the ppy/osu! project's cloning utilities.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 is compatible. net5.0-windows net5.0-windows was computed. net6.0 net6.0 is compatible. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 is compatible. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 is compatible. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 1 NuGet packages that depend on ktsu.DeepClone:
| Package | Downloads |
|---|---|
|
ktsu.Coder.Core
Placeholder description, a single line concise description of the project, suitable for the package description in the nuget list UI. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.12-pre.1 | 85 | 2/17/2026 |
| 2.0.11 | 176 | 2/16/2026 |
| 2.0.11-pre.1 | 73 | 2/16/2026 |
| 2.0.10 | 132 | 2/14/2026 |
| 2.0.9 | 134 | 2/14/2026 |
| 2.0.9-pre.5 | 74 | 2/6/2026 |
| 2.0.9-pre.4 | 76 | 2/5/2026 |
| 2.0.9-pre.3 | 78 | 2/3/2026 |
| 2.0.9-pre.2 | 78 | 2/1/2026 |
| 2.0.9-pre.1 | 76 | 1/31/2026 |
| 2.0.8 | 158 | 1/30/2026 |
| 2.0.7 | 136 | 1/30/2026 |
| 2.0.7-pre.2 | 76 | 1/28/2026 |
| 2.0.7-pre.1 | 74 | 1/26/2026 |
| 2.0.6 | 148 | 1/26/2026 |
| 2.0.6-pre.3 | 188 | 11/24/2025 |
| 2.0.6-pre.2 | 147 | 11/23/2025 |
| 2.0.6-pre.1 | 136 | 11/23/2025 |
| 2.0.5 | 273 | 11/14/2025 |
| 2.0.4 | 470 | 8/25/2025 |
## v2.0.11 (patch)
Changes since v2.0.10:
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.11-pre.1 (prerelease)
Changes since v2.0.10:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.10 (patch)
Changes since v2.0.9:
- Remove legacy build scripts ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.9 (patch)
Changes since v2.0.8:
- Refactor null checks in DeepCloneContainerExtensions and update Polyfill package version to 9.7.7 ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.9-pre.5 (prerelease)
Changes since v2.0.9-pre.4:
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\update-winget-manifests.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.9-pre.4 (prerelease)
Changes since v2.0.9-pre.3:
- Sync scripts\update-winget-manifests.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.9-pre.3 (prerelease)
Changes since v2.0.9-pre.2:
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.9-pre.2 (prerelease)
Changes since v2.0.9-pre.1:
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.9-pre.1 (prerelease)
No significant changes detected since v2.0.9.
## v2.0.8 (patch)
Changes since v2.0.7:
- Enhance assertions in tests with descriptive messages for clarity ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.7 (patch)
Changes since v2.0.6:
- Remove .github\workflows\project.yml ([@matt-edmondson](https://github.com/matt-edmondson))
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .gitignore ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\update-winget-manifests.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.7-pre.2 (prerelease)
Changes since v2.0.7-pre.1:
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync global.json ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Merge remote-tracking branch 'refs/remotes/origin/main' ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .gitignore ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.7-pre.1 (prerelease)
No significant changes detected since v2.0.7.
## v2.0.6 (patch)
Changes since v2.0.5:
- Update project files and tests for improved functionality and dependencies ([@matt-edmondson](https://github.com/matt-edmondson))
- Add CLAUDE.md for project guidance and documentation ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.6-pre.3 (prerelease)
Changes since v2.0.6-pre.2:
- Sync scripts\update-winget-manifests.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.6-pre.2 (prerelease)
Changes since v2.0.6-pre.1:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v2.0.6-pre.1 (prerelease)
No significant changes detected since v2.0.6.
## v2.0.5 (patch)
Changes since v2.0.4:
- Update project configuration and CI/CD settings ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.4 (patch)
Changes since v2.0.3:
- Migrate to PolySharp polyfills ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.3 (patch)
Changes since v2.0.2:
- Enhance CI/CD workflows and update SDK management ([@matt-edmondson](https://github.com/matt-edmondson))
- Refactor DeepClone project and update dependencies ([@matt-edmondson](https://github.com/matt-edmondson))
- Add project configuration files and refactor DeepClone project structure ([@matt-edmondson](https://github.com/matt-edmondson))
- Update configuration files and improve build scripts ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.2 (patch)
Changes since v2.0.1:
- Update SDK version and improve code readability ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.1 (patch)
Changes since v2.0.0:
- [patch] Fix version ([@matt-edmondson](https://github.com/matt-edmondson))
- [patch] Fix version ([@matt-edmondson](https://github.com/matt-edmondson))
- [patch] Fix version ([@matt-edmondson](https://github.com/matt-edmondson))
## v2.0.1-pre.1 (prerelease)
No significant changes detected since v2.0.1.
## v2.0.0 (major)
Changes since 1.0.0:
- [major] Complete rewrite ([@matt-edmondson](https://github.com/matt-edmondson))
- Refactor Get-VersionNotes function to improve commit message filtering by replacing pipeline usage with a foreach loop. This change enhances clarity and performance in handling version updates and skip conditions. ([@matt-edmondson](https://github.com/matt-edmondson))
- Refine Get-BuildConfiguration function to ensure commit messages are processed as an array, improving the filtering of non-skip commits. This update enhances the accuracy of release eligibility checks by handling string outputs more effectively. ([@matt-edmondson](https://github.com/matt-edmondson))
- Refactor Get-BuildConfiguration function to ensure proper array handling of commit messages. This change guarantees accurate filtering of non-skip commits by enforcing array treatment, enhancing the reliability of release eligibility checks. ([@matt-edmondson](https://github.com/matt-edmondson))
- Enhance PSBuild module documentation and functions. Updated function descriptions for clarity, added examples, and improved parameter details across various functions. ([@matt-edmondson](https://github.com/matt-edmondson))
- Remove Directory.Build.props and Directory.Build.targets files, delete unused scripts for managing metadata, changelog, license, and versioning. Add copyright headers to IDeepClonable.cs and TestCloneable.cs. ([@matt-edmondson](https://github.com/matt-edmondson))
- Update project metadata and enhance documentation with detailed usage examples and API reference ([@matt-edmondson](https://github.com/matt-edmondson))
- Add LICENSE template ([@matt-edmondson](https://github.com/matt-edmondson))
- Apply new editorconfig ([@matt-edmondson](https://github.com/matt-edmondson))
- Fix changelog script to handle prerelease version drops correctly ([@matt-edmondson](https://github.com/matt-edmondson))
- Add mailmap ([@matt-edmondson](https://github.com/matt-edmondson))
- Add scripts for automated metadata generation and versioning ([@matt-edmondson](https://github.com/matt-edmondson))
- Renamed metadata files ([@matt-edmondson](https://github.com/matt-edmondson))
- Replace LICENSE file with LICENSE.md and update copyright information ([@matt-edmondson](https://github.com/matt-edmondson))
- Update test method names and replace LICENSE file ([@matt-edmondson](https://github.com/matt-edmondson))
- Remove unnecessary PackageReference from DeepClone.Test project ([@matt-edmondson](https://github.com/matt-edmondson))
- Update repository URL in README.md ([@matt-edmondson](https://github.com/matt-edmondson))
- Add test project, update README, and remove .gitattributes ([@matt-edmondson](https://github.com/matt-edmondson))
- Update VERSION ([@matt-edmondson](https://github.com/matt-edmondson))
- Migrate ktsu.io to ktsu namespace ([@matt-edmondson](https://github.com/matt-edmondson))
- Update VERSION ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.3.2-pre.7 (prerelease)
Changes since v1.3.2-pre.6:
## v1.3.2-pre.6 (prerelease)
Changes since v1.3.2-pre.5:
## v1.3.2-pre.5 (prerelease)
Changes since v1.3.2-pre.4:
## v1.3.2-pre.4 (prerelease)
Changes since v1.3.2-pre.3:
## v1.3.2-pre.3 (prerelease)
Changes since v1.3.2-pre.2:
## v1.3.2-pre.2 (prerelease)
Changes since v1.3.2-pre.1:
## v1.3.2-pre.1 (prerelease)
Changes since v1.3.1:
- Sync scripts\PSBuild.psm1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.3.1 (patch)
Changes since v1.3.0:
- Remove Directory.Build.props and Directory.Build.targets files, delete unused scripts for managing metadata, changelog, license, and versioning. Add copyright headers to IDeepClonable.cs and TestCloneable.cs. ([@matt-edmondson](https://github.com/matt-edmondson))
- Update project metadata and enhance documentation with detailed usage examples and API reference ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.3.1-pre.2 (prerelease)
Changes since v1.3.1-pre.1:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .editorconfig ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .runsettings ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.3.1-pre.1 (prerelease)
No significant changes detected since v1.3.1.
## v1.3.0 (minor)
Changes since v1.2.0:
- Add LICENSE template ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.2.1-pre.2 (prerelease)
Changes since v1.2.1-pre.1:
- Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\make-changelog.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.2.1-pre.1 (prerelease)
Changes since v1.2.0:
- Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\make-changelog.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .editorconfig ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .gitignore ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.2.0 (minor)
Changes since v1.1.0:
- Apply new editorconfig ([@matt-edmondson](https://github.com/matt-edmondson))
- Fix changelog script to handle prerelease version drops correctly ([@matt-edmondson](https://github.com/matt-edmondson))
- Add mailmap ([@matt-edmondson](https://github.com/matt-edmondson))
- Add scripts for automated metadata generation and versioning ([@matt-edmondson](https://github.com/matt-edmondson))
- Renamed metadata files ([@matt-edmondson](https://github.com/matt-edmondson))
- Replace LICENSE file with LICENSE.md and update copyright information ([@matt-edmondson](https://github.com/matt-edmondson))
- Update test method names and replace LICENSE file ([@matt-edmondson](https://github.com/matt-edmondson))
- Remove unnecessary PackageReference from DeepClone.Test project ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.17-pre.3 (prerelease)
Changes since v1.1.17-pre.2:
- Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\make-changelog.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.17-pre.2 (prerelease)
Changes since v1.1.17-pre.1:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.17-pre.1 (prerelease)
Changes since v1.1.16:
- Fix changelog script to handle prerelease version drops correctly ([@matt-edmondson](https://github.com/matt-edmondson))
- Add mailmap ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.16
No significant changes detected since v1.1.16-pre.29.
## v1.1.16-pre.29 (prerelease)
Changes since v1.1.16-pre.28:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.28 (prerelease)
Changes since v1.1.16-pre.27:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.27 (prerelease)
Changes since v1.1.16-pre.26:
## v1.1.16-pre.26 (prerelease)
Changes since v1.1.16-pre.25:
## v1.1.16-pre.25 (prerelease)
Changes since v1.1.16-pre.24:
- Bump MSTest from 3.7.2 to 3.7.3 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.1.16-pre.24 (prerelease)
Changes since v1.1.16-pre.23:
## v1.1.16-pre.23 (prerelease)
Changes since v1.1.16-pre.22:
## v1.1.16-pre.22 (prerelease)
Changes since v1.1.16-pre.21:
- Bump MSTest from 3.7.1 to 3.7.2 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.1.16-pre.21 (prerelease)
Changes since v1.1.16-pre.20:
- Bump coverlet.collector from 6.0.3 to 6.0.4 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.1.16-pre.20 (prerelease)
Changes since v1.1.16-pre.19:
## v1.1.16-pre.19 (prerelease)
Changes since v1.1.16-pre.18:
## v1.1.16-pre.18 (prerelease)
Changes since v1.1.16-pre.17:
- Bump MSTest from 3.7.0 to 3.7.1 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.1.16-pre.17 (prerelease)
Changes since v1.1.16-pre.16:
## v1.1.16-pre.16 (prerelease)
Changes since v1.1.16-pre.15:
## v1.1.16-pre.15 (prerelease)
Changes since v1.1.16-pre.14:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.14 (prerelease)
Changes since v1.1.16-pre.13:
- Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync scripts\make-changelog.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.13 (prerelease)
Changes since v1.1.16-pre.12:
## v1.1.16-pre.12 (prerelease)
Changes since v1.1.16-pre.11:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.11 (prerelease)
Changes since v1.1.16-pre.10:
## v1.1.16-pre.10 (prerelease)
Changes since v1.1.16-pre.9:
## v1.1.16-pre.9 (prerelease)
Changes since v1.1.16-pre.8:
- Sync scripts\make-version.ps1 ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.8 (prerelease)
Changes since v1.1.16-pre.7:
- Fix changelog script to handle prerelease version drops correctly ([@matt-edmondson](https://github.com/matt-edmondson))
- Add mailmap ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.16-pre.7 (prerelease)
Changes since v1.1.16-pre.6:
- Add scripts for automated metadata generation and versioning ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.16-pre.6 (prerelease)
Changes since v1.1.16-pre.5:
## v1.1.16-pre.5 (prerelease)
Changes since v1.1.16-pre.4:
- Bump coverlet.collector from 6.0.2 to 6.0.3 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.1.16-pre.4 (prerelease)
Changes since v1.1.16-pre.3:
## v1.1.16-pre.3 (prerelease)
Changes since v1.1.16-pre.2:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.2 (prerelease)
Changes since v1.1.16-pre.1:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.16-pre.1 (prerelease)
No significant changes detected since v1.1.16.
## v1.1.15-pre.1 (prerelease)
Changes since v1.1.14:
- Renamed metadata files ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.14 (patch)
Changes since v1.1.13:
- Sync icon.png ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.13 (patch)
Changes since v1.1.12:
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.12 (patch)
Changes since v1.1.11:
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.11 (patch)
Changes since v1.1.10:
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.10 (patch)
Changes since v1.1.9:
- Replace LICENSE file with LICENSE.md and update copyright information ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.10-pre.1 (prerelease)
Changes since v1.1.10:
- Renamed metadata files ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.9 (patch)
Changes since v1.1.8:
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.8 (patch)
Changes since v1.1.7:
- Update test method names and replace LICENSE file ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.7 (patch)
Changes since v1.1.6:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.6 (patch)
Changes since v1.1.5:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.5 (patch)
Changes since v1.1.4:
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.4 (patch)
Changes since v1.1.3:
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.1.3 (patch)
Changes since v1.1.2:
- Bump MSTest.TestFramework from 3.6.3 to 3.6.4 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.1.2 (patch)
Changes since v1.1.1:
- Bump MSTest.TestAdapter from 3.6.3 to 3.6.4 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.1.1 (patch)
Changes since v1.1.0:
- Remove unnecessary PackageReference from DeepClone.Test project ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.1.0 (minor)
Changes since 1.0.0:
- Update repository URL in README.md ([@matt-edmondson](https://github.com/matt-edmondson))
- Add test project, update README, and remove .gitattributes ([@matt-edmondson](https://github.com/matt-edmondson))
- Update VERSION ([@matt-edmondson](https://github.com/matt-edmondson))
- Migrate ktsu.io to ktsu namespace ([@matt-edmondson](https://github.com/matt-edmondson))
- Update VERSION ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.0.18 (patch)
Changes since v1.0.17:
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.17 (patch)
Changes since v1.0.16:
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.16 (patch)
Changes since v1.0.15:
- Sync Directory.Build.targets ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync Directory.Build.props ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.15 (patch)
Changes since v1.0.14:
- Bump MSTest.TestFramework from 3.6.2 to 3.6.3 ([@dependabot[bot]](https://github.com/dependabot[bot]))
- Bump Microsoft.NET.Test.Sdk in the microsoft group ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.0.14 (patch)
Changes since v1.0.13:
- Bump MSTest.TestAdapter from 3.6.2 to 3.6.3 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.0.13 (patch)
Changes since v1.0.12:
- Bump MSTest.TestAdapter from 3.6.1 to 3.6.2 ([@dependabot[bot]](https://github.com/dependabot[bot]))
- Bump MSTest.TestFramework from 3.6.1 to 3.6.2 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.0.12 (patch)
Changes since v1.0.11:
- Bump MSTest.TestFramework from 3.6.0 to 3.6.1 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.0.11 (patch)
Changes since v1.0.10:
- Bump MSTest.TestAdapter from 3.6.0 to 3.6.1 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.0.10 (patch)
Changes since v1.0.9:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.9 (patch)
Changes since v1.0.8:
- Update VERSION to 1.0.9 ([@matt-edmondson](https://github.com/matt-edmondson))
## v1.0.8 (patch)
Changes since v1.0.7:
- Sync .github\dependabot.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\dependabot.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.7 (patch)
Changes since v1.0.6:
- Sync .github\workflows\dependabot-merge.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.6 (patch)
Changes since v1.0.5:
- Sync .github\workflows\dependabot-merge.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.5 (patch)
Changes since v1.0.4:
- Sync .github\workflows\dependabot-merge.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.4 (patch)
Changes since v1.0.3:
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dependabot-merge.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dependabot-merge.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Bump MSTest.TestAdapter from 3.5.2 to 3.6.0 ([@dependabot[bot]](https://github.com/dependabot[bot]))
- Bump MSTest.TestFramework from 3.5.2 to 3.6.0 ([@dependabot[bot]](https://github.com/dependabot[bot]))
## v1.0.3 (patch)
Changes since v1.0.2:
- Sync .github\dependabot.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
- Sync .github\workflows\dotnet.yml ([@ktsu[bot]](https://github.com/ktsu[bot]))
## v1.0.2 (major)
- Update VERSION ([@matt-edmondson](https://github.com/matt-edmondson))
- Migrate ktsu.io to ktsu namespace ([@matt-edmondson](https://github.com/matt-edmondson))
- Update VERSION ([@matt-edmondson](https://github.com/matt-edmondson))
- Update DeepClone.csproj ([@matt-edmondson](https://github.com/matt-edmondson))
- Initial commit ([@matt-edmondson](https://github.com/matt-edmondson))