diff --git a/Source/Cloning/CloneFactoryTest.cs b/Source/Cloning/CloneFactoryTest.cs
index 1dd5d9c..7c99fbf 100644
--- a/Source/Cloning/CloneFactoryTest.cs
+++ b/Source/Cloning/CloneFactoryTest.cs
@@ -78,6 +78,14 @@ namespace Nuclex.Support.Cloning {
public TestReferenceType[,][] ReferenceTypeArrayField;
/// An array property of reference types
public TestReferenceType[,][] ReferenceTypeArrayProperty { get; set; }
+ /// A reference type field that's always null
+ public TestReferenceType AlwaysNullField;
+ /// A reference type property that's always null
+ public TestReferenceType AlwaysNullProperty { get; set; }
+ /// A property that only has a getter
+ public TestReferenceType GetOnlyProperty { get { return null; } }
+ /// A property that only has a s
+ public TestReferenceType SetOnlyProperty { set { } }
}
@@ -104,11 +112,44 @@ namespace Nuclex.Support.Cloning {
public TestReferenceType[,][] ReferenceTypeArrayField;
/// An array property of reference types
public TestReferenceType[,][] ReferenceTypeArrayProperty { get; set; }
+ /// A reference type field that's always null
+ public TestReferenceType AlwaysNullField;
+ /// A reference type property that's always null
+ public TestReferenceType AlwaysNullProperty { get; set; }
+ /// A property that only has a getter
+ public TestReferenceType GetOnlyProperty { get { return null; } }
+ /// A property that only has a s
+ public TestReferenceType SetOnlyProperty { set { } }
}
#endregion // struct HierarchicalReferenceType
+ #region class ClassWithoutDefaultConstructor
+
+ /// A class that does not have a default constructor
+ public class ClassWithoutDefaultConstructor {
+
+ ///
+ /// Initializes a new instance of the class without default constructor
+ ///
+ /// Dummy value that will be saved by the instance
+ public ClassWithoutDefaultConstructor(int dummy) {
+ this.dummy = dummy;
+ }
+
+ /// Dummy value that has been saved by the instance
+ public int Dummy {
+ get { return this.dummy; }
+ }
+
+ /// Dummy value that has been saved by the instance
+ private int dummy;
+
+ }
+
+ #endregion // class ClassWithoutDefaultConstructor
+
///
/// Verifies that a cloned object exhibits the expected state for the type of
/// clone that has been performed
diff --git a/Source/Cloning/ExpressionTreeCloner.PropertyBased.cs b/Source/Cloning/ExpressionTreeCloner.PropertyBased.cs
index 52cac35..550bbfe 100644
--- a/Source/Cloning/ExpressionTreeCloner.PropertyBased.cs
+++ b/Source/Cloning/ExpressionTreeCloner.PropertyBased.cs
@@ -213,44 +213,46 @@ namespace Nuclex.Support.Cloning {
);
for(int index = 0; index < propertyInfos.Length; ++index) {
PropertyInfo propertyInfo = propertyInfos[index];
- Type propertyType = propertyInfo.PropertyType;
+ if(propertyInfo.CanRead && propertyInfo.CanWrite) {
+ Type propertyType = propertyInfo.PropertyType;
- if(propertyType.IsPrimitive || (propertyType == typeof(string))) {
- transferExpressions.Add(
- Expression.Assign(
- Expression.Property(clone, propertyInfo),
- Expression.Property(original, propertyInfo)
- )
- );
- } else if(propertyType.IsValueType) {
- ParameterExpression originalProperty = Expression.Variable(propertyType);
- variables.Add(originalProperty);
- transferExpressions.Add(
- Expression.Assign(
- originalProperty, Expression.Property(original, propertyInfo)
- )
- );
+ if(propertyType.IsPrimitive || (propertyType == typeof(string))) {
+ transferExpressions.Add(
+ Expression.Assign(
+ Expression.Property(clone, propertyInfo),
+ Expression.Property(original, propertyInfo)
+ )
+ );
+ } else if(propertyType.IsValueType) {
+ ParameterExpression originalProperty = Expression.Variable(propertyType);
+ variables.Add(originalProperty);
+ transferExpressions.Add(
+ Expression.Assign(
+ originalProperty, Expression.Property(original, propertyInfo)
+ )
+ );
- ParameterExpression clonedProperty = Expression.Variable(propertyType);
- variables.Add(clonedProperty);
- transferExpressions.Add(
- Expression.Assign(clonedProperty, Expression.New(propertyType))
- );
+ ParameterExpression clonedProperty = Expression.Variable(propertyType);
+ variables.Add(clonedProperty);
+ transferExpressions.Add(
+ Expression.Assign(clonedProperty, Expression.New(propertyType))
+ );
- generateShallowPropertyBasedComplexCloneExpressions(propertyType, originalProperty, clonedProperty, transferExpressions, variables);
+ generateShallowPropertyBasedComplexCloneExpressions(propertyType, originalProperty, clonedProperty, transferExpressions, variables);
- transferExpressions.Add(
- Expression.Assign(
- Expression.Property(clone, propertyInfo), clonedProperty
- )
- );
- } else {
- transferExpressions.Add(
- Expression.Assign(
- Expression.Property(clone, propertyInfo),
- Expression.Property(original, propertyInfo)
- )
- );
+ transferExpressions.Add(
+ Expression.Assign(
+ Expression.Property(clone, propertyInfo), clonedProperty
+ )
+ );
+ } else {
+ transferExpressions.Add(
+ Expression.Assign(
+ Expression.Property(clone, propertyInfo),
+ Expression.Property(original, propertyInfo)
+ )
+ );
+ }
}
}
}
@@ -503,52 +505,54 @@ namespace Nuclex.Support.Cloning {
);
for(int index = 0; index < propertyInfos.Length; ++index) {
PropertyInfo propertyInfo = propertyInfos[index];
- Type propertyType = propertyInfo.PropertyType;
+ if(propertyInfo.CanRead && propertyInfo.CanWrite) {
+ Type propertyType = propertyInfo.PropertyType;
- if(propertyType.IsPrimitive || (propertyType == typeof(string))) {
- // Primitive types and strings can be transferred by simple assignment
- transferExpressions.Add(
- Expression.Assign(
- Expression.Property(clone, propertyInfo),
- Expression.Property(original, propertyInfo)
- )
- );
- } else if(propertyType.IsValueType) {
- ParameterExpression originalProperty = Expression.Variable(propertyType);
- variables.Add(originalProperty);
- ParameterExpression clonedProperty = Expression.Variable(propertyType);
- variables.Add(clonedProperty);
+ if(propertyType.IsPrimitive || (propertyType == typeof(string))) {
+ // Primitive types and strings can be transferred by simple assignment
+ transferExpressions.Add(
+ Expression.Assign(
+ Expression.Property(clone, propertyInfo),
+ Expression.Property(original, propertyInfo)
+ )
+ );
+ } else if(propertyType.IsValueType) {
+ ParameterExpression originalProperty = Expression.Variable(propertyType);
+ variables.Add(originalProperty);
+ ParameterExpression clonedProperty = Expression.Variable(propertyType);
+ variables.Add(clonedProperty);
- transferExpressions.Add(
- Expression.Assign(
- originalProperty, Expression.Property(original, propertyInfo)
- )
- );
- transferExpressions.Add(
- Expression.Assign(clonedProperty, Expression.New(propertyType))
- );
+ transferExpressions.Add(
+ Expression.Assign(
+ originalProperty, Expression.Property(original, propertyInfo)
+ )
+ );
+ transferExpressions.Add(
+ Expression.Assign(clonedProperty, Expression.New(propertyType))
+ );
- // A nested value type is part of the parent and will have its properties directly
- // assigned without boxing, new instance creation or anything like that.
- generatePropertyBasedComplexTypeTransferExpressions(
- propertyType,
- originalProperty,
- clonedProperty,
- variables,
- transferExpressions
- );
+ // A nested value type is part of the parent and will have its properties directly
+ // assigned without boxing, new instance creation or anything like that.
+ generatePropertyBasedComplexTypeTransferExpressions(
+ propertyType,
+ originalProperty,
+ clonedProperty,
+ variables,
+ transferExpressions
+ );
- transferExpressions.Add(
- Expression.Assign(
- Expression.Property(clone, propertyInfo),
- clonedProperty
- )
- );
+ transferExpressions.Add(
+ Expression.Assign(
+ Expression.Property(clone, propertyInfo),
+ clonedProperty
+ )
+ );
- } else {
- generatePropertyBasedReferenceTypeTransferExpressions(
- original, clone, transferExpressions, variables, propertyInfo, propertyType
- );
+ } else {
+ generatePropertyBasedReferenceTypeTransferExpressions(
+ original, clone, transferExpressions, variables, propertyInfo, propertyType
+ );
+ }
}
}
}
diff --git a/Source/Cloning/ExpressionTreeCloner.Test.cs b/Source/Cloning/ExpressionTreeCloner.Test.cs
index 5b520b3..42c3a6e 100644
--- a/Source/Cloning/ExpressionTreeCloner.Test.cs
+++ b/Source/Cloning/ExpressionTreeCloner.Test.cs
@@ -45,6 +45,19 @@ namespace Nuclex.Support.Cloning {
Assert.IsNull(this.cloneFactory.ShallowPropertyClone