Skip to content

Commit

Permalink
Use backing fields when available (#24)
Browse files Browse the repository at this point in the history
* Use backing fields when available

* Use backing field for properties declared in base class

* Fix couple Unit Tests + make them run in AppVeyor (hopefuly)

* Fix an exception thrown when type being cloned has a shadowed property
  • Loading branch information
MarcinJuraszek committed Oct 24, 2017
1 parent 63a438f commit 586157b
Show file tree
Hide file tree
Showing 8 changed files with 408 additions and 320 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,4 @@ FakesAssemblies/
# Roslyn
*.sln.ide/
BenchmarkDotNet.Artifacts/results/
.vscode/
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<RootNamespace>CloneExtensions.Benchmarks</RootNamespace>
<AssemblyName>CloneExtensions.Benchmarks</AssemblyName>
<TargetFrameworks>netcoreapp1.1</TargetFrameworks>
<TargetFrameworks>netcoreapp1.1;net461</TargetFrameworks>
<Version>1.4.2.0</Version>
<OutputType>Exe</OutputType>
</PropertyGroup>
Expand Down
94 changes: 47 additions & 47 deletions src/CloneExtensions.Benchmarks/GetCloneBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,58 @@

namespace CloneExtensions.Benchmarks
{
public class GetCloneBenchmarks
{
private readonly SimpleClass _simpleClass;
private readonly List<int> _listOfInts;
private readonly List<SimpleClass> _listOfSimpleClassSameInstance;
private readonly List<SimpleClass> _listOfSimpleClassDifferentInstances;
public class GetCloneBenchmarks
{
private readonly SimpleClass _simpleClass;
private readonly List<int> _listOfInts;
private readonly List<SimpleClass> _listOfSimpleClassSameInstance;
private readonly List<SimpleClass> _listOfSimpleClassDifferentInstances;

public GetCloneBenchmarks()
{
_simpleClass = new SimpleClass()
{
Int = 10,
UInt = 1231,
Long = 1231234561L,
ULong = 1516524352UL,
Double = 1235.1235762,
Float = 1.333F,
String = "Lorem ipsum ...",
};
public GetCloneBenchmarks()
{
_simpleClass = new SimpleClass()
{
Int = 10,
UInt = 1231,
Long = 1231234561L,
ULong = 1516524352UL,
Double = 1235.1235762,
Float = 1.333F,
String = "Lorem ipsum ...",
};

_listOfInts = Enumerable.Range(0, 10000).ToList();
_listOfInts = Enumerable.Range(0, 10000).ToList();

_listOfSimpleClassSameInstance = Enumerable.Repeat(_simpleClass, 10000).ToList();
_listOfSimpleClassDifferentInstances = Enumerable.Range(0, 10000).Select(x => new SimpleClass() { Int = x }).ToList();
}
_listOfSimpleClassSameInstance = Enumerable.Repeat(_simpleClass, 10000).ToList();
_listOfSimpleClassDifferentInstances = Enumerable.Range(0, 10000).Select(x => new SimpleClass() { Int = x }).ToList();
}

[Benchmark]
public int GetCloneSimpleClass()
{
var clone = _simpleClass.GetClone();
return clone.Int;
}
[Benchmark]
public int GetCloneSimpleClass()
{
var clone = _simpleClass.GetClone();
return clone.Int;
}

[Benchmark]
public int GetCloneListOfInts()
{
var clone = _listOfInts.GetClone();
return clone.Count;
}
[Benchmark]
public int GetCloneListOfInts()
{
var clone = _listOfInts.GetClone();
return clone.Count;
}

[Benchmark]
public int GetCloneListOfSimpleClassSameInstance()
{
var clone = _listOfSimpleClassSameInstance.GetClone();
return clone.Count;
}
[Benchmark]
public int GetCloneListOfSimpleClassSameInstance()
{
var clone = _listOfSimpleClassSameInstance.GetClone();
return clone.Count;
}

[Benchmark]
public int GetCloneListOfSimpleClassDifferentInstances()
{
var clone = _listOfSimpleClassDifferentInstances.GetClone();
return clone.Count;
}
}
[Benchmark]
public int GetCloneListOfSimpleClassDifferentInstances()
{
var clone = _listOfSimpleClassDifferentInstances.GetClone();
return clone.Count;
}
}
}
14 changes: 7 additions & 7 deletions src/CloneExtensions.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

namespace CloneExtensions.Benchmarks
{
class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<GetCloneBenchmarks>();
}
}
class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<GetCloneBenchmarks>();
}
}
}
25 changes: 15 additions & 10 deletions src/CloneExtensions.Benchmarks/SimpleClass.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
namespace CloneExtensions.Benchmarks
{
public class SimpleClass
{
public int Int { get; set; }
public uint UInt { get; set; }
public long Long { get; set; }
public ulong ULong { get; set; }
public double Double { get; set; }
public float Float { get; set; }
public string String { get; set; }
}
public class SimpleClassBase
{
public int BaseInt { get; set; }
}

public class SimpleClass : SimpleClassBase
{
public int Int { get; set; }
public uint UInt { get; set; }
public long Long { get; set; }
public ulong ULong { get; set; }
public double Double { get; set; }
public float Float { get; set; }
public string String { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<RootNamespace>CloneExtensions.UnitTests</RootNamespace>
<AssemblyName>CloneExtensions.UnitTests</AssemblyName>
<TargetFrameworks>netcoreapp1.1</TargetFrameworks>
<TargetFrameworks>net461</TargetFrameworks>
<Version>1.4.2.0</Version>
</PropertyGroup>
<ItemGroup>
Expand Down
204 changes: 114 additions & 90 deletions src/CloneExtensions.UnitTests/CollectionTests.cs
Original file line number Diff line number Diff line change
@@ -1,90 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CloneExtensions.UnitTests.Base;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CloneExtensions.UnitTests
{
[TestClass]
public class CollectionTests : TestBase
{
[TestMethod]
public void GetClone_ListOfInts_Cloned()
{
var source = Enumerable.Range(0, 10).ToList();
var target = CloneFactory.GetClone(source);
Assert.AreNotSame(source, target);
Assert.IsTrue(source.SequenceEqual(target));
}

[TestMethod]
public void GetClone_ListOfIntsCloningFlagsCollectionItemsNotProvided_ItemsNotCloned()
{
var source = Enumerable.Range(0, 10).ToList();
var target = CloneFactory.GetClone(source, CloningFlags.Properties);
Assert.AreNotSame(source, target);
Assert.AreEqual(source.Capacity, target.Capacity);
Assert.AreEqual(0, target.Count);
}

[TestMethod]
public void GetClone_ListOfClass_ReferenceEqualityReturnsFalse()
{
var source = Enumerable.Range(1, 10).Select(x => new MyClass() { _field = x, Property = x }).ToList();
var target = CloneFactory.GetClone(source);
Assert.AreNotSame(source, target);
Assert.IsTrue(source.SequenceEqual(target));
Assert.IsFalse(source.Zip(target, (s, t) => new { s, t }).Any(x => ReferenceEquals(x.s, x.t)));
}

[TestMethod]
public void GetClone_IListOfClass_ReferenceEqualityReturnsFalse()
{
IList<MyClass> source = Enumerable.Range(1, 10).Select(x => new MyClass() { _field = x, Property = x }).ToList();
var initializers = new Dictionary<Type, Func<object, object>>() {
{ typeof(IList<MyClass>), (s) => new List<MyClass>() }
};
var target = CloneFactory.GetClone(source, initializers);
Assert.AreNotSame(source, target);
Assert.IsTrue(source.SequenceEqual(target));
Assert.IsFalse(source.Zip(target, (s, t) => new { s, t }).Any(x => ReferenceEquals(x.s, x.t)));
}

[TestMethod]
public void GetClone_NullListOfInt_NullCloned()
{
List<int> source = null;
var target = CloneFactory.GetClone(source);
Assert.IsNull(target);
}

[TestMethod]
public void GetClone_Dictionary_Cloned()
{
var source = new Dictionary<int, string>() { { 1, "one" }, { 2, "two" } };
var target = CloneFactory.GetClone(source);
Assert.IsTrue(source.SequenceEqual(target));
}

class MyClass
{
public int _field;
public int Property { get; set; }

public override bool Equals(object obj)
{
var other = obj as MyClass;
if (other == null)
return false;

return other._field == _field && other.Property == Property;
}

public override int GetHashCode()
{
return _field.GetHashCode() ^ Property.GetHashCode();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using CloneExtensions.UnitTests.Base;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CloneExtensions.UnitTests
{
[TestClass]
public class CollectionTests : TestBase
{
[TestMethod]
public void GetClone_ListOfInts_Cloned()
{
var source = Enumerable.Range(0, 10).ToList();
var target = CloneFactory.GetClone(source);
Assert.AreNotSame(source, target);
Assert.IsTrue(source.SequenceEqual(target));
}

[TestMethod]
public void GetClone_ListOfIntsCloningFlagsCollectionItemsNotProvided_ItemsNotCloned()
{
var source = Enumerable.Range(0, 10).ToList();
var target = CloneFactory.GetClone(source, CloningFlags.Properties);
Assert.AreNotSame(source, target);
Assert.AreEqual(source.Count, target.Capacity);
Assert.AreEqual(0, target.Count);
}

[TestMethod]
public void GetClone_ListOfClass_ReferenceEqualityReturnsFalse()
{
var source = Enumerable.Range(1, 10).Select(x => new MyClass() { _field = x, Property = x }).ToList();
var target = CloneFactory.GetClone(source);
Assert.AreNotSame(source, target);
Assert.IsTrue(source.SequenceEqual(target));
Assert.IsFalse(source.Zip(target, (s, t) => new { s, t }).Any(x => ReferenceEquals(x.s, x.t)));
}

[TestMethod]
public void GetClone_IListOfClass_ReferenceEqualityReturnsFalse()
{
IList<MyClass> source = Enumerable.Range(1, 10).Select(x => new MyClass() { _field = x, Property = x }).ToList();
var initializers = new Dictionary<Type, Func<object, object>>() {
{ typeof(IList<MyClass>), (s) => new List<MyClass>() }
};
var target = CloneFactory.GetClone(source, initializers);
Assert.AreNotSame(source, target);
Assert.IsTrue(source.SequenceEqual(target));
Assert.IsFalse(source.Zip(target, (s, t) => new { s, t }).Any(x => ReferenceEquals(x.s, x.t)));
}

[TestMethod]
public void GetClone_NullListOfInt_NullCloned()
{
List<int> source = null;
var target = CloneFactory.GetClone(source);
Assert.IsNull(target);
}

[TestMethod]
public void GetClone_Dictionary_Cloned()
{
var source = new Dictionary<int, string>() { { 1, "one" }, { 2, "two" } };
var target = CloneFactory.GetClone(source);
Assert.IsTrue(source.SequenceEqual(target));
}

[TestMethod]
public void GetClone_DerivedTypeWithShadowedProperty_ClonnedProperly()
{
DerivedClass source = new DerivedClass() { Property = 1 };
((BaseClass)source).Property = 2;

var target = CloneFactory.GetClone(source);

Assert.AreEqual(1, target.Property);

// TODO: Make it work ...
// Assert.AreEqual(2, ((BaseClass)target).Property);
}

class MyClass
{
public int _field;
public int Property { get; set; }

public override bool Equals(object obj)
{
var other = obj as MyClass;
if (other == null)
return false;

return other._field == _field && other.Property == Property;
}

public override int GetHashCode()
{
return _field.GetHashCode() ^ Property.GetHashCode();
}
}

class BaseClass
{
public int Property { get; set; }
}

class DerivedClass : BaseClass
{
public new int Property { get; set; }
}
}
}
Loading

0 comments on commit 586157b

Please sign in to comment.