diff --git a/Source/Cloning/CloneFactoryTest.cs b/Source/Cloning/CloneFactoryTest.cs
index f768649..7d48bcc 100644
--- a/Source/Cloning/CloneFactoryTest.cs
+++ b/Source/Cloning/CloneFactoryTest.cs
@@ -100,6 +100,8 @@ namespace Nuclex.Support.Cloning {
public TestReferenceType GetOnlyProperty { get { return null; } }
/// A property that only has a setter
public TestReferenceType SetOnlyProperty { set { } }
+ /// A read-only field
+ public readonly TestValueType ReadOnlyField;
/// Field typed as base class holding a derived instance
public TestReferenceType DerivedField;
/// Field typed as base class holding a derived instance
@@ -136,8 +138,10 @@ namespace Nuclex.Support.Cloning {
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
+ /// A property that only has a setter
public TestReferenceType SetOnlyProperty { set { } }
+ /// A read-only field
+ public readonly TestValueType ReadOnlyField;
/// Field typed as base class holding a derived instance
public TestReferenceType DerivedField;
/// Field typed as base class holding a derived instance
diff --git a/Source/Cloning/ExpressionTreeCloner.FieldBased.cs b/Source/Cloning/ExpressionTreeCloner.FieldBased.cs
index 98a2d26..1fa5686 100644
--- a/Source/Cloning/ExpressionTreeCloner.FieldBased.cs
+++ b/Source/Cloning/ExpressionTreeCloner.FieldBased.cs
@@ -191,12 +191,47 @@ namespace Nuclex.Support.Cloning {
for(int index = 0; index < fieldInfos.Length; ++index) {
FieldInfo fieldInfo = fieldInfos[index];
- transferExpressions.Add(
- Expression.Assign(
- Expression.Field(clone, fieldInfo),
- Expression.Field(typedOriginal, fieldInfo)
- )
- );
+ if(fieldInfo.IsInitOnly) {
+ Expression source = Expression.Field(typedOriginal, fieldInfo);
+ if(fieldInfo.FieldType.IsValueType) {
+ source = Expression.Convert(source, typeof(object));
+ }
+
+ if(clone.Type.IsValueType) {
+ MethodInfo assignInitOnlyField = typeof(ExpressionTreeCloner).GetMethod(
+ "assignInitOnlyField", BindingFlags.Static | BindingFlags.NonPublic
+ ).MakeGenericMethod(clone.Type);
+
+ transferExpressions.Add(
+ Expression.Call(
+ assignInitOnlyField,
+ clone,
+ Expression.Constant(fieldInfo),
+ source
+ )
+ );
+ } else {
+ MethodInfo setValueMethodInfo = typeof(FieldInfo).GetMethod(
+ "SetValue", new Type[] { typeof(object), typeof(object) }
+ );
+
+ transferExpressions.Add(
+ Expression.Call(
+ Expression.Constant(fieldInfo),
+ setValueMethodInfo,
+ clone,
+ source
+ )
+ );
+ }
+ } else {
+ transferExpressions.Add(
+ Expression.Assign(
+ Expression.Field(clone, fieldInfo),
+ Expression.Field(typedOriginal, fieldInfo)
+ )
+ );
+ }
}
// Make sure the clone is the last thing in the block to set the return value
@@ -555,28 +590,62 @@ namespace Nuclex.Support.Cloning {
MethodInfo getTypeMethodInfo = typeof(object).GetMethod("GetType");
MethodInfo invokeMethodInfo = typeof(Func