Index: /trunk/sources/HeuristicLab.Persistence/3.3/Core/DataMemberAccessor.cs
===================================================================
--- /trunk/sources/HeuristicLab.Persistence/3.3/Core/DataMemberAccessor.cs	(revision 5323)
+++ /trunk/sources/HeuristicLab.Persistence/3.3/Core/DataMemberAccessor.cs	(revision 5324)
@@ -150,10 +150,5 @@
         return GenerateFieldGetter(fieldInfo);
       } else if (memberInfo.MemberType == MemberTypes.Property) {
-        PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
-        if (!propertyInfo.CanRead || !propertyInfo.CanWrite) {
-          throw new PersistenceException(
-            "Storable properties must implement both a Get and a Set Accessor. ");
-        }
-        return GeneratePropertyGetter(propertyInfo);
+        return GeneratePropertyGetter((PropertyInfo)memberInfo);
       } else {
         throw new PersistenceException(
@@ -172,10 +167,5 @@
         return GenerateFieldSetter(fieldInfo);
       } else if (memberInfo.MemberType == MemberTypes.Property) {
-        PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
-        if (!propertyInfo.CanRead || !propertyInfo.CanWrite) {
-          throw new PersistenceException(
-            "Storable properties must implement both a Get and a Set Accessor. ");
-        }
-        return GeneratePropertySetter(propertyInfo);
+        return GeneratePropertySetter((PropertyInfo)memberInfo);
       } else {
         throw new PersistenceException(
@@ -201,5 +191,5 @@
 
     /// <summary>
-    /// Generates a dynamically compiled sett to access fields (even private ones).
+    /// Generates a dynamically compiled setter to access fields (even private ones).
     /// </summary>
     /// <param name="fieldInfo">The field info.</param>
@@ -223,9 +213,12 @@
     /// <returns>A Func&lt;object, object&gt;</returns>
     public static Func<object, object> GeneratePropertyGetter(PropertyInfo propertyInfo) {
+      MethodInfo getter = propertyInfo.GetGetMethod(true);
+      if (getter == null)
+        return null;
       DynamicMethod dm = new DynamicMethod("", typeof(object), new Type[] { typeof(object) }, propertyInfo.DeclaringType, true);
       ILGenerator ilgen = dm.GetILGenerator();
       ilgen.Emit(OpCodes.Ldarg_0);
       ilgen.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
-      ilgen.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod(true));
+      ilgen.Emit(OpCodes.Callvirt, getter);
       ilgen.Emit(OpCodes.Box, propertyInfo.PropertyType);
       ilgen.Emit(OpCodes.Ret);
@@ -239,4 +232,7 @@
     /// <returns>An Action&lt;object, object%gt;</returns>
     public static Action<object, object> GeneratePropertySetter(PropertyInfo propertyInfo) {
+      MethodInfo setter = propertyInfo.GetSetMethod(true);
+      if (setter == null)
+        return null;
       DynamicMethod dm = new DynamicMethod("", null, new Type[] { typeof(object), typeof(object) }, propertyInfo.DeclaringType, true);
       ILGenerator ilgen = dm.GetILGenerator();
@@ -245,5 +241,5 @@
       ilgen.Emit(OpCodes.Ldarg_1);
       ilgen.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
-      ilgen.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod(true));
+      ilgen.Emit(OpCodes.Callvirt, setter);
       ilgen.Emit(OpCodes.Ret);
       return (Action<object, object>)dm.CreateDelegate(typeof(Action<object, object>));
Index: /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableAttribute.cs
===================================================================
--- /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableAttribute.cs	(revision 5323)
+++ /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableAttribute.cs	(revision 5324)
@@ -56,4 +56,11 @@
 
     /// <summary>
+    /// Allow storable attribute on properties with only a getter or a setter. These
+    /// properties will then by either only serialized but not deserialized or only
+    /// deserialized (if stored) but not serialized again.
+    /// </summary>
+    public bool AllowOneWay { get; set; }
+
+    /// <summary>
     /// Returns a <see cref="System.String"/> that represents this instance.
     /// </summary>
Index: /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableMemberInfo.cs
===================================================================
--- /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableMemberInfo.cs	(revision 5323)
+++ /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableMemberInfo.cs	(revision 5324)
@@ -23,4 +23,5 @@
 using System.Reflection;
 using System.Text;
+using HeuristicLab.Persistence.Core;
 
 namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable {
@@ -43,7 +44,17 @@
       DefaultValue = attribute.DefaultValue;
       MemberInfo = memberInfo;
+      if (!attribute.AllowOneWay)
+        CheckPropertyAccess(memberInfo as PropertyInfo);
     }
-    public StorableMemberInfo(MemberInfo memberInfo) {
+    public StorableMemberInfo(MemberInfo memberInfo, bool allowOneWay) {
       MemberInfo = memberInfo;
+      if (!allowOneWay)
+        CheckPropertyAccess(memberInfo as PropertyInfo);
+    }
+    private static void CheckPropertyAccess(PropertyInfo propertyInfo) {
+      if (propertyInfo == null)
+        return;
+      if (!propertyInfo.CanRead || !propertyInfo.CanWrite)
+        throw new PersistenceException("Properties must be readable and writable or explicity enable one way serialization.");
     }
     public void SetDisentangledName(string name) {
@@ -51,6 +62,18 @@
         DisentangledName = name;
     }
+    /// <summary>
+    /// Gets the type who first defined this property in the class hierarchy when the
+    /// property has subsequently been overridden but not shadowed with <code>new</code>.
+    /// </summary>
+    /// <returns>The properties base type.</returns>
     public Type GetPropertyDeclaringBaseType() {
-      return ((PropertyInfo)MemberInfo).GetGetMethod(true).GetBaseDefinition().DeclaringType;
+      PropertyInfo pi = MemberInfo as PropertyInfo;
+      if (pi == null)
+        throw new PersistenceException("fields don't have a declaring base type, directly use FullyQualifiedMemberName instead");
+      if (pi.CanRead)
+        return pi.GetGetMethod(true).GetBaseDefinition().DeclaringType;
+      if (pi.CanWrite)
+        return pi.GetSetMethod(true).GetBaseDefinition().DeclaringType;
+      throw new InvalidOperationException("property has neigher a getter nor a setter.");
     }
   }
Index: /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableReflection.cs
===================================================================
--- /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableReflection.cs	(revision 5323)
+++ /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableReflection.cs	(revision 5324)
@@ -58,5 +58,4 @@
         }
       }
-
       return DisentangleNameMapping(storableMembers);
     }
@@ -108,9 +107,21 @@
             !memberInfo.Name.StartsWith("<") &&
             !memberInfo.Name.EndsWith("k__BackingField"))
-          storableMembers.Add(new StorableMemberInfo(memberInfo));
-      }
-    }
-
-
+          storableMembers.Add(new StorableMemberInfo(memberInfo, false));
+      }
+    }
+
+    /// <summary>
+    /// Ascertain distinct names for all fields and properties. This method takes care
+    /// of disentangling equal names from different class hiarachy levels.
+    /// 
+    /// Field names are replaced with their fully qualified name which includes
+    /// the class names where they were declared.
+    /// 
+    /// Property names are first reduced to unqiue accessors that are not overrides of
+    /// each other and the replaced with their fully qualified name if more than one
+    /// accessor remains.
+    /// </summary>
+    /// <param name="storableMemberInfos"></param>
+    /// <returns></returns>
     private static IEnumerable<StorableMemberInfo> DisentangleNameMapping(
         IEnumerable<StorableMemberInfo> storableMemberInfos) {
@@ -138,4 +149,10 @@
     }
 
+    /// <summary>
+    /// Merges property accessors that are overrides of each other but differentiates if a new
+    /// property that shadows older implementations has been introduced with <code>new</code>.
+    /// </summary>
+    /// <param name="members">A list of <code>StorableMemberInfo</code>s for properties of the same type.</param>
+    /// <returns>A fieltered <code>IEnumerable</code> of propery infos.</returns>
     private static IEnumerable<StorableMemberInfo> MergePropertyAccessors(List<StorableMemberInfo> members) {
       var uniqueAccessors = new Dictionary<Type, StorableMemberInfo>();
Index: /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs	(revision 5323)
+++ /trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs	(revision 5324)
@@ -118,5 +118,6 @@
     public IEnumerable<Tag> Decompose(object obj) {
       foreach (var accessor in GetStorableAccessors(obj.GetType())) {
-        yield return new Tag(accessor.Name, accessor.Get(obj));
+        if (accessor.Get != null)
+          yield return new Tag(accessor.Name, accessor.Get(obj));
       }
     }
@@ -151,8 +152,10 @@
       }
       foreach (var accessor in GetStorableAccessors(instance.GetType())) {
-        if (memberDict.ContainsKey(accessor.Name)) {
-          accessor.Set(instance, memberDict[accessor.Name].Value);
-        } else if (accessor.DefaultValue != null) {
-          accessor.Set(instance, accessor.DefaultValue);
+        if (accessor.Set != null) {
+          if (memberDict.ContainsKey(accessor.Name)) {
+            accessor.Set(instance, memberDict[accessor.Name].Value);
+          } else if (accessor.DefaultValue != null) {
+            accessor.Set(instance, accessor.DefaultValue);
+          }
         }
       }
Index: /trunk/sources/HeuristicLab.Persistence/3.3/Tests/UseCases.cs
===================================================================
--- /trunk/sources/HeuristicLab.Persistence/3.3/Tests/UseCases.cs	(revision 5323)
+++ /trunk/sources/HeuristicLab.Persistence/3.3/Tests/UseCases.cs	(revision 5324)
@@ -31,4 +31,5 @@
 using HeuristicLab.Persistence.Auxiliary;
 using HeuristicLab.Persistence.Core;
+using HeuristicLab.Persistence.Core.Tokens;
 using HeuristicLab.Persistence.Default.CompositeSerializers;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -606,6 +607,5 @@
         XmlGenerator.Serialize(c, tempFile);
         Assert.Fail("Exception not thrown");
-      }
-      catch (PersistenceException) {
+      } catch (PersistenceException) {
       }
     }
@@ -619,6 +619,5 @@
         XmlGenerator.Serialize(s, tempFile);
         Assert.Fail("Exception expected");
-      }
-      catch (PersistenceException) { }
+      } catch (PersistenceException) { }
       List<int> newList = (List<int>)XmlParser.Deserialize(tempFile);
       Assert.AreEqual(list[0], newList[0]);
@@ -659,6 +658,5 @@
         }
         Assert.Fail("Exception expected");
-      }
-      catch (PersistenceException px) {
+      } catch (PersistenceException px) {
         Assert.AreEqual(3, px.Data.Count);
       }
@@ -688,6 +686,5 @@
         d = new Deserializer(XmlParser.ParseTypeCache(new StringReader(newTypeString)));
         Assert.Fail("Exception expected");
-      }
-      catch (PersistenceException x) {
+      } catch (PersistenceException x) {
         Assert.IsTrue(x.Message.Contains("incompatible"));
       }
@@ -698,6 +695,5 @@
         d = new Deserializer(XmlParser.ParseTypeCache(new StringReader(newTypeString)));
         Assert.Fail("Exception expected");
-      }
-      catch (PersistenceException x) {
+      } catch (PersistenceException x) {
         Assert.IsTrue(x.Message.Contains("newer"));
       }
@@ -866,6 +862,5 @@
         ExplodingDefaultConstructor newX = (ExplodingDefaultConstructor)XmlParser.Deserialize(tempFile);
         Assert.Fail("Exception expected");
-      }
-      catch (PersistenceException pe) {
+      } catch (PersistenceException pe) {
         Assert.AreEqual(pe.InnerException.Message, "this constructor will always fail");
       }
@@ -878,6 +873,5 @@
         XmlGenerator.Serialize(ns, tempFile);
         Assert.Fail("PersistenceException expected");
-      }
-      catch (PersistenceException x) {
+      } catch (PersistenceException x) {
         Assert.IsTrue(x.Message.Contains(new StorableSerializer().JustifyRejection(typeof(NonSerializable))));
       }
@@ -1161,4 +1155,79 @@
     }
 
+    [StorableClass]
+    public class ReadOnlyFail {
+      [Storable]
+      public string ReadOnly {
+        get { return "fail"; }
+      }
+    }
+
+    [TestMethod]
+    public void TestReadOnlyFail() {
+      try {
+        XmlGenerator.Serialize(new ReadOnlyFail(), tempFile);
+        Assert.Fail("Exception expected");
+      } catch (PersistenceException) {
+      } catch {
+        Assert.Fail("PersistenceException expected");
+      }
+    }
+
+
+    [StorableClass]
+    public class WriteOnlyFail {
+      [Storable]
+      public string WriteOnly {
+        set { throw new InvalidOperationException("this property should never be set."); }
+      }
+    }
+
+    [TestMethod]
+    public void TestWriteOnlyFail() {
+      try {
+        XmlGenerator.Serialize(new WriteOnlyFail(), tempFile);
+        Assert.Fail("Exception expected");
+      } catch (PersistenceException) {
+      } catch {
+        Assert.Fail("PersistenceException expected.");
+      }
+    }
+
+    [StorableClass]
+    public class OneWayTest {
+      public OneWayTest() { this.value = "default"; }
+      public string value;
+      [Storable(AllowOneWay=true)]
+      public string ReadOnly {
+        get { return "ReadOnly"; }
+      }
+      [Storable(AllowOneWay=true)]
+      public string WriteOnly {
+        set { this.value = value; }
+      }
+    }
+
+    [TestMethod]
+    public void TestOneWaySerialization() {
+      var test = new OneWayTest();
+      var serializer = new Serializer(test, ConfigurationService.Instance.GetDefaultConfig(new XmlFormat()));
+      var it = serializer.GetEnumerator();
+      it.MoveNext();
+      Assert.AreEqual("ROOT", ((BeginToken)it.Current).Name); it.MoveNext();
+      Assert.AreEqual("ReadOnly", ((PrimitiveToken)it.Current).Name); it.MoveNext();
+      Assert.AreEqual("ROOT", ((EndToken)it.Current).Name); it.MoveNext();
+      var deserializer = new Deserializer(new[] { 
+        new TypeMapping(0, typeof(OneWayTest).AssemblyQualifiedName, typeof(StorableSerializer).AssemblyQualifiedName),
+        new TypeMapping(1, typeof(string).AssemblyQualifiedName, typeof(String2XmlSerializer).AssemblyQualifiedName) });
+      var newTest = (OneWayTest)deserializer.Deserialize(new ISerializationToken[] {
+        new BeginToken("ROOT", 0, 0),
+        new PrimitiveToken("WriteOnly", 1, 1, new XmlString("<![CDATA[serial data]]>")),
+        new EndToken("ROOT", 0, 0)
+      });
+      Assert.AreEqual("serial data", newTest.value);
+    }
+
+
+
     [ClassInitialize]
     public static void Initialize(TestContext testContext) {
