Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build new expression for types without parameter less constructor #35

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/CloneExtensions.UnitTests/ComplexTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,23 @@ public void GetClone_CircularDependency_ItemsClonedCorrectly()
Assert.AreSame(target.First, target.Second, "Are the same");
}

[TestMethod]
public void GetClone_ConstructorClass_ClonnedProperly()
{
var source = new ConstructorClass(null, 3, DateTime.Now, new List<string>(), null, default)
{
PropertyA = 3,
PropertyB = Guid.NewGuid().ToString(),
PropertyC = DateTime.Now
};

var target = CloneFactory.GetClone(source);

Assert.AreEqual(source.PropertyA, target.PropertyA);
Assert.AreEqual(source.PropertyB, target.PropertyB);
Assert.AreEqual(source.PropertyC, target.PropertyC);
}

[TestMethod]
public void GetClone_DerivedTypeWithShadowedProperty_ClonnedProperly()
{
Expand Down Expand Up @@ -226,5 +243,23 @@ class DerivedClassOne : BaseClassOne
// use the default implementation for VirtualProperty2
public override string VirtualProperty3 { get; set; }
}

class ConstructorClass
{
public ConstructorClass(
BaseClassOne a,
int? b,
DateTime c,
List<string> d,
IInterface e,
SimpleStruct f)
{

}

public int PropertyA { get; set; }
public string PropertyB { get; set; }
public DateTime PropertyC { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,39 @@ private Expression GetInitializationExpression()
var funcInvokeCall = Expression.Call(dictIndex, "Invoke", null, Expression.Convert(Source, typeof(object)));
var initializerCall = Expression.Convert(funcInvokeCall, _type);

// parameterless constructor
var constructor = _type.GetConstructor(new Type[0]);

return Expression.IfThenElse(
containsKeyCall,
Expression.Assign(Target, initializerCall),
(_type.IsAbstract() || _type.IsInterface() || (!_type.IsValueType() && constructor == null)) ?
(_type.IsAbstract() || _type.IsInterface()) ?
Helpers.GetThrowInvalidOperationExceptionExpression(_type) :
Expression.Assign(
Target,
_type.IsValueType() ? (Expression)Source : Expression.New(_type)
_type.IsValueType() ? (Expression)Source : GetNewExpressionFor(_type)
)
);
}

private static NewExpression GetNewExpressionFor(Type objType)
{
ConstructorInfo ctor = objType
.GetConstructors()
.OrderBy(x => x.GetParameters().Length)
.First();

return
Expression.New
(
ctor,
ctor.GetParameters().Select(p =>
p.IsOptional
? Expression.Convert(Expression.Constant(p.DefaultValue), p.ParameterType)
: p.ParameterType.IsAbstract() || p.ParameterType.IsInterface() ||
(p.ParameterType.IsValueType() && Nullable.GetUnderlyingType(p.ParameterType) == null)
? Expression.Default(p.ParameterType)
: (Expression)GetNewExpressionFor(p.ParameterType))
);
}

private Expression GetFieldsCloneExpression(Func<Type, Expression, Expression> getItemCloneExpression)
{
var fields = from f in _type.GetTypeInfo().GetFields(BindingFlags.Public | BindingFlags.Instance)
Expand Down