Changeset 5324
- Timestamp:
- 01/18/11 15:50:23 (14 years ago)
- Location:
- trunk/sources/HeuristicLab.Persistence/3.3
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/HeuristicLab.Persistence/3.3/Core/DataMemberAccessor.cs
r4068 r5324 150 150 return GenerateFieldGetter(fieldInfo); 151 151 } else if (memberInfo.MemberType == MemberTypes.Property) { 152 PropertyInfo propertyInfo = (PropertyInfo)memberInfo; 153 if (!propertyInfo.CanRead || !propertyInfo.CanWrite) { 154 throw new PersistenceException( 155 "Storable properties must implement both a Get and a Set Accessor. "); 156 } 157 return GeneratePropertyGetter(propertyInfo); 152 return GeneratePropertyGetter((PropertyInfo)memberInfo); 158 153 } else { 159 154 throw new PersistenceException( … … 172 167 return GenerateFieldSetter(fieldInfo); 173 168 } else if (memberInfo.MemberType == MemberTypes.Property) { 174 PropertyInfo propertyInfo = (PropertyInfo)memberInfo; 175 if (!propertyInfo.CanRead || !propertyInfo.CanWrite) { 176 throw new PersistenceException( 177 "Storable properties must implement both a Get and a Set Accessor. "); 178 } 179 return GeneratePropertySetter(propertyInfo); 169 return GeneratePropertySetter((PropertyInfo)memberInfo); 180 170 } else { 181 171 throw new PersistenceException( … … 201 191 202 192 /// <summary> 203 /// Generates a dynamically compiled sett to access fields (even private ones).193 /// Generates a dynamically compiled setter to access fields (even private ones). 204 194 /// </summary> 205 195 /// <param name="fieldInfo">The field info.</param> … … 223 213 /// <returns>A Func<object, object></returns> 224 214 public static Func<object, object> GeneratePropertyGetter(PropertyInfo propertyInfo) { 215 MethodInfo getter = propertyInfo.GetGetMethod(true); 216 if (getter == null) 217 return null; 225 218 DynamicMethod dm = new DynamicMethod("", typeof(object), new Type[] { typeof(object) }, propertyInfo.DeclaringType, true); 226 219 ILGenerator ilgen = dm.GetILGenerator(); 227 220 ilgen.Emit(OpCodes.Ldarg_0); 228 221 ilgen.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); 229 ilgen.Emit(OpCodes.Callvirt, propertyInfo.GetGetMethod(true));222 ilgen.Emit(OpCodes.Callvirt, getter); 230 223 ilgen.Emit(OpCodes.Box, propertyInfo.PropertyType); 231 224 ilgen.Emit(OpCodes.Ret); … … 239 232 /// <returns>An Action<object, object%gt;</returns> 240 233 public static Action<object, object> GeneratePropertySetter(PropertyInfo propertyInfo) { 234 MethodInfo setter = propertyInfo.GetSetMethod(true); 235 if (setter == null) 236 return null; 241 237 DynamicMethod dm = new DynamicMethod("", null, new Type[] { typeof(object), typeof(object) }, propertyInfo.DeclaringType, true); 242 238 ILGenerator ilgen = dm.GetILGenerator(); … … 245 241 ilgen.Emit(OpCodes.Ldarg_1); 246 242 ilgen.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); 247 ilgen.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod(true));243 ilgen.Emit(OpCodes.Callvirt, setter); 248 244 ilgen.Emit(OpCodes.Ret); 249 245 return (Action<object, object>)dm.CreateDelegate(typeof(Action<object, object>)); -
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableAttribute.cs
r4068 r5324 56 56 57 57 /// <summary> 58 /// Allow storable attribute on properties with only a getter or a setter. These 59 /// properties will then by either only serialized but not deserialized or only 60 /// deserialized (if stored) but not serialized again. 61 /// </summary> 62 public bool AllowOneWay { get; set; } 63 64 /// <summary> 58 65 /// Returns a <see cref="System.String"/> that represents this instance. 59 66 /// </summary> -
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableMemberInfo.cs
r4068 r5324 23 23 using System.Reflection; 24 24 using System.Text; 25 using HeuristicLab.Persistence.Core; 25 26 26 27 namespace HeuristicLab.Persistence.Default.CompositeSerializers.Storable { … … 43 44 DefaultValue = attribute.DefaultValue; 44 45 MemberInfo = memberInfo; 46 if (!attribute.AllowOneWay) 47 CheckPropertyAccess(memberInfo as PropertyInfo); 45 48 } 46 public StorableMemberInfo(MemberInfo memberInfo ) {49 public StorableMemberInfo(MemberInfo memberInfo, bool allowOneWay) { 47 50 MemberInfo = memberInfo; 51 if (!allowOneWay) 52 CheckPropertyAccess(memberInfo as PropertyInfo); 53 } 54 private static void CheckPropertyAccess(PropertyInfo propertyInfo) { 55 if (propertyInfo == null) 56 return; 57 if (!propertyInfo.CanRead || !propertyInfo.CanWrite) 58 throw new PersistenceException("Properties must be readable and writable or explicity enable one way serialization."); 48 59 } 49 60 public void SetDisentangledName(string name) { … … 51 62 DisentangledName = name; 52 63 } 64 /// <summary> 65 /// Gets the type who first defined this property in the class hierarchy when the 66 /// property has subsequently been overridden but not shadowed with <code>new</code>. 67 /// </summary> 68 /// <returns>The properties base type.</returns> 53 69 public Type GetPropertyDeclaringBaseType() { 54 return ((PropertyInfo)MemberInfo).GetGetMethod(true).GetBaseDefinition().DeclaringType; 70 PropertyInfo pi = MemberInfo as PropertyInfo; 71 if (pi == null) 72 throw new PersistenceException("fields don't have a declaring base type, directly use FullyQualifiedMemberName instead"); 73 if (pi.CanRead) 74 return pi.GetGetMethod(true).GetBaseDefinition().DeclaringType; 75 if (pi.CanWrite) 76 return pi.GetSetMethod(true).GetBaseDefinition().DeclaringType; 77 throw new InvalidOperationException("property has neigher a getter nor a setter."); 55 78 } 56 79 } -
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableReflection.cs
r4068 r5324 58 58 } 59 59 } 60 61 60 return DisentangleNameMapping(storableMembers); 62 61 } … … 108 107 !memberInfo.Name.StartsWith("<") && 109 108 !memberInfo.Name.EndsWith("k__BackingField")) 110 storableMembers.Add(new StorableMemberInfo(memberInfo)); 111 } 112 } 113 114 109 storableMembers.Add(new StorableMemberInfo(memberInfo, false)); 110 } 111 } 112 113 /// <summary> 114 /// Ascertain distinct names for all fields and properties. This method takes care 115 /// of disentangling equal names from different class hiarachy levels. 116 /// 117 /// Field names are replaced with their fully qualified name which includes 118 /// the class names where they were declared. 119 /// 120 /// Property names are first reduced to unqiue accessors that are not overrides of 121 /// each other and the replaced with their fully qualified name if more than one 122 /// accessor remains. 123 /// </summary> 124 /// <param name="storableMemberInfos"></param> 125 /// <returns></returns> 115 126 private static IEnumerable<StorableMemberInfo> DisentangleNameMapping( 116 127 IEnumerable<StorableMemberInfo> storableMemberInfos) { … … 138 149 } 139 150 151 /// <summary> 152 /// Merges property accessors that are overrides of each other but differentiates if a new 153 /// property that shadows older implementations has been introduced with <code>new</code>. 154 /// </summary> 155 /// <param name="members">A list of <code>StorableMemberInfo</code>s for properties of the same type.</param> 156 /// <returns>A fieltered <code>IEnumerable</code> of propery infos.</returns> 140 157 private static IEnumerable<StorableMemberInfo> MergePropertyAccessors(List<StorableMemberInfo> members) { 141 158 var uniqueAccessors = new Dictionary<Type, StorableMemberInfo>(); -
trunk/sources/HeuristicLab.Persistence/3.3/Default/CompositeSerializers/Storable/StorableSerializer.cs
r5292 r5324 118 118 public IEnumerable<Tag> Decompose(object obj) { 119 119 foreach (var accessor in GetStorableAccessors(obj.GetType())) { 120 yield return new Tag(accessor.Name, accessor.Get(obj)); 120 if (accessor.Get != null) 121 yield return new Tag(accessor.Name, accessor.Get(obj)); 121 122 } 122 123 } … … 151 152 } 152 153 foreach (var accessor in GetStorableAccessors(instance.GetType())) { 153 if (memberDict.ContainsKey(accessor.Name)) { 154 accessor.Set(instance, memberDict[accessor.Name].Value); 155 } else if (accessor.DefaultValue != null) { 156 accessor.Set(instance, accessor.DefaultValue); 154 if (accessor.Set != null) { 155 if (memberDict.ContainsKey(accessor.Name)) { 156 accessor.Set(instance, memberDict[accessor.Name].Value); 157 } else if (accessor.DefaultValue != null) { 158 accessor.Set(instance, accessor.DefaultValue); 159 } 157 160 } 158 161 } -
trunk/sources/HeuristicLab.Persistence/3.3/Tests/UseCases.cs
r5290 r5324 31 31 using HeuristicLab.Persistence.Auxiliary; 32 32 using HeuristicLab.Persistence.Core; 33 using HeuristicLab.Persistence.Core.Tokens; 33 34 using HeuristicLab.Persistence.Default.CompositeSerializers; 34 35 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; … … 606 607 XmlGenerator.Serialize(c, tempFile); 607 608 Assert.Fail("Exception not thrown"); 608 } 609 catch (PersistenceException) { 609 } catch (PersistenceException) { 610 610 } 611 611 } … … 619 619 XmlGenerator.Serialize(s, tempFile); 620 620 Assert.Fail("Exception expected"); 621 } 622 catch (PersistenceException) { } 621 } catch (PersistenceException) { } 623 622 List<int> newList = (List<int>)XmlParser.Deserialize(tempFile); 624 623 Assert.AreEqual(list[0], newList[0]); … … 659 658 } 660 659 Assert.Fail("Exception expected"); 661 } 662 catch (PersistenceException px) { 660 } catch (PersistenceException px) { 663 661 Assert.AreEqual(3, px.Data.Count); 664 662 } … … 688 686 d = new Deserializer(XmlParser.ParseTypeCache(new StringReader(newTypeString))); 689 687 Assert.Fail("Exception expected"); 690 } 691 catch (PersistenceException x) { 688 } catch (PersistenceException x) { 692 689 Assert.IsTrue(x.Message.Contains("incompatible")); 693 690 } … … 698 695 d = new Deserializer(XmlParser.ParseTypeCache(new StringReader(newTypeString))); 699 696 Assert.Fail("Exception expected"); 700 } 701 catch (PersistenceException x) { 697 } catch (PersistenceException x) { 702 698 Assert.IsTrue(x.Message.Contains("newer")); 703 699 } … … 866 862 ExplodingDefaultConstructor newX = (ExplodingDefaultConstructor)XmlParser.Deserialize(tempFile); 867 863 Assert.Fail("Exception expected"); 868 } 869 catch (PersistenceException pe) { 864 } catch (PersistenceException pe) { 870 865 Assert.AreEqual(pe.InnerException.Message, "this constructor will always fail"); 871 866 } … … 878 873 XmlGenerator.Serialize(ns, tempFile); 879 874 Assert.Fail("PersistenceException expected"); 880 } 881 catch (PersistenceException x) { 875 } catch (PersistenceException x) { 882 876 Assert.IsTrue(x.Message.Contains(new StorableSerializer().JustifyRejection(typeof(NonSerializable)))); 883 877 } … … 1161 1155 } 1162 1156 1157 [StorableClass] 1158 public class ReadOnlyFail { 1159 [Storable] 1160 public string ReadOnly { 1161 get { return "fail"; } 1162 } 1163 } 1164 1165 [TestMethod] 1166 public void TestReadOnlyFail() { 1167 try { 1168 XmlGenerator.Serialize(new ReadOnlyFail(), tempFile); 1169 Assert.Fail("Exception expected"); 1170 } catch (PersistenceException) { 1171 } catch { 1172 Assert.Fail("PersistenceException expected"); 1173 } 1174 } 1175 1176 1177 [StorableClass] 1178 public class WriteOnlyFail { 1179 [Storable] 1180 public string WriteOnly { 1181 set { throw new InvalidOperationException("this property should never be set."); } 1182 } 1183 } 1184 1185 [TestMethod] 1186 public void TestWriteOnlyFail() { 1187 try { 1188 XmlGenerator.Serialize(new WriteOnlyFail(), tempFile); 1189 Assert.Fail("Exception expected"); 1190 } catch (PersistenceException) { 1191 } catch { 1192 Assert.Fail("PersistenceException expected."); 1193 } 1194 } 1195 1196 [StorableClass] 1197 public class OneWayTest { 1198 public OneWayTest() { this.value = "default"; } 1199 public string value; 1200 [Storable(AllowOneWay=true)] 1201 public string ReadOnly { 1202 get { return "ReadOnly"; } 1203 } 1204 [Storable(AllowOneWay=true)] 1205 public string WriteOnly { 1206 set { this.value = value; } 1207 } 1208 } 1209 1210 [TestMethod] 1211 public void TestOneWaySerialization() { 1212 var test = new OneWayTest(); 1213 var serializer = new Serializer(test, ConfigurationService.Instance.GetDefaultConfig(new XmlFormat())); 1214 var it = serializer.GetEnumerator(); 1215 it.MoveNext(); 1216 Assert.AreEqual("ROOT", ((BeginToken)it.Current).Name); it.MoveNext(); 1217 Assert.AreEqual("ReadOnly", ((PrimitiveToken)it.Current).Name); it.MoveNext(); 1218 Assert.AreEqual("ROOT", ((EndToken)it.Current).Name); it.MoveNext(); 1219 var deserializer = new Deserializer(new[] { 1220 new TypeMapping(0, typeof(OneWayTest).AssemblyQualifiedName, typeof(StorableSerializer).AssemblyQualifiedName), 1221 new TypeMapping(1, typeof(string).AssemblyQualifiedName, typeof(String2XmlSerializer).AssemblyQualifiedName) }); 1222 var newTest = (OneWayTest)deserializer.Deserialize(new ISerializationToken[] { 1223 new BeginToken("ROOT", 0, 0), 1224 new PrimitiveToken("WriteOnly", 1, 1, new XmlString("<![CDATA[serial data]]>")), 1225 new EndToken("ROOT", 0, 0) 1226 }); 1227 Assert.AreEqual("serial data", newTest.value); 1228 } 1229 1230 1231 1163 1232 [ClassInitialize] 1164 1233 public static void Initialize(TestContext testContext) {
Note: See TracChangeset
for help on using the changeset viewer.