UnitTests/BinarySerialisationVersioningTests.cs
/// <summary>
/// Support properties to be replaced on future versions of the type and for the serialised data generated from that future version to be deserialised assemblies that
/// have older versions of the type - this will only work if the replaced properties continue to exist on the future version but as computed properties that return (and
/// set, if the type should be mutable) values derived from the new data AND if the computed properties have the [Deprecated] attribute on them.
/// </summary>
Support properties to be replaced on future versions of the type and for the serialised data generated from that future version to be deserialised assemblies that
have older versions of the type - this will only work if the replaced properties continue to exist on the future version but as computed properties that return (and
set, if the type should be mutable) values derived from the new data AND if the computed properties have the [Deprecated] attribute on them.
Support properties to be replaced on future versions of the type and for the serialised data generated from that future version to be deserialised assemblies that have older versions of the type - this will only work if the replaced properties continue to exist on the future version but as computed properties that return ( and set if the type should be mutable ) values derived from the new data AND if the computed properties have the [ Deprecated ] attribute on them .
[Fact]
		public static void DeprecatedPropertyShouldBeSerialisedAsIfItIsAnAutoProperty()
		{
			const string idPropertyName = "Id";
			const int hardCodedIdValueForDeprecatedProperty = 123;
			var typeWithDeprecatedProperty = ConstructType(
				GetModuleBuilder("DynamicAssemblyFor" + GetMyName(), new Version(1, 0)),
				"MyClass",
				fields: new Tuple<string, Type>[0],
				optionalFinisher: typeBuilder =>
				{
					var propertyBuilder = typeBuilder.DefineProperty(idPropertyName, PropertyAttributes.None, typeof(int), parameterTypes: Type.EmptyTypes);
					propertyBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(DeprecatedAttribute).GetConstructor(new[] { typeof(string) }), new object[] { null }));
					var getterBuilder = typeBuilder.DefineMethod("get_" + idPropertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(int), parameterTypes: Type.EmptyTypes);
					var ilGenerator = getterBuilder.GetILGenerator();
					ilGenerator.Emit(OpCodes.Ldc_I4, hardCodedIdValueForDeprecatedProperty);
					ilGenerator.Emit(OpCodes.Ret);
					propertyBuilder.SetGetMethod(getterBuilder);
				}
			);
			var instance = Activator.CreateInstance(typeWithDeprecatedProperty);
			var serialisedData = BinarySerialisation.Serialise(instance);
			var idBackingFieldName = BackingFieldHelpers.GetBackingFieldName(idPropertyName);
			var typeThatStillHasThePropertyOnIt = ConstructType(
				GetModuleBuilder("DynamicAssemblyFor" + GetMyName(), new Version(1, 0)),
				"MyClass",
				new[] { Tuple.Create(idBackingFieldName, typeof(int)) }
			);
			var deserialised = ResolveDynamicAssembliesWhilePerformingAction(
				() => Deserialise(serialisedData, typeThatStillHasThePropertyOnIt),
				typeThatStillHasThePropertyOnIt
			);
			var idBackingFieldOnDestination = typeThatStillHasThePropertyOnIt.GetField(idBackingFieldName);
			Assert.Equal(123, idBackingFieldOnDestination.GetValue(deserialised));
		}
[ Fact ] public static void DeprecatedPropertyShouldBeSerialisedAsIfItIsAnAutoProperty ( ) { const string idPropertyName = " " ; const int hardCodedIdValueForDeprecatedProperty = 123 ; var typeWithDeprecatedProperty = ConstructType ( GetModuleBuilder ( " " + GetMyName ( ) , new Version ( 1 , 0 ) ) , " " , fields : new Tuple < string , Type > [ 0 ] , optionalFinisher : typeBuilder => { var propertyBuilder = typeBuilder . DefineProperty ( idPropertyName , PropertyAttributes . None , typeof ( int ) , parameterTypes : Type . EmptyTypes ) ; propertyBuilder . SetCustomAttribute ( new CustomAttributeBuilder ( typeof ( DeprecatedAttribute ) . GetConstructor ( new [ ] { typeof ( string ) } ) , new object [ ] { null } ) ) ; var getterBuilder = typeBuilder . DefineMethod ( " " + idPropertyName , MethodAttributes . Public | MethodAttributes . SpecialName | MethodAttributes . HideBySig , typeof ( int ) , parameterTypes : Type . EmptyTypes ) ; var ilGenerator = getterBuilder . GetILGenerator ( ) ; ilGenerator . Emit ( OpCodes . Ldc_I4 , hardCodedIdValueForDeprecatedProperty ) ; ilGenerator . Emit ( OpCodes . Ret ) ; propertyBuilder . SetGetMethod ( getterBuilder ) ; } ) ; var instance = Activator . CreateInstance ( typeWithDeprecatedProperty ) ; var serialisedData = BinarySerialisation . Serialise ( instance ) ; var idBackingFieldName = BackingFieldHelpers . GetBackingFieldName ( idPropertyName ) ; var typeThatStillHasThePropertyOnIt = ConstructType ( GetModuleBuilder ( " " + GetMyName ( ) , new Version ( 1 , 0 ) ) , " " , new [ ] { Tuple . Create ( idBackingFieldName , typeof ( int ) ) } ) ; var deserialised = ResolveDynamicAssembliesWhilePerformingAction ( ( ) => Deserialise ( serialisedData , typeThatStillHasThePropertyOnIt ) , typeThatStillHasThePropertyOnIt ) ; var idBackingFieldOnDestination = typeThatStillHasThePropertyOnIt . GetField ( idBackingFieldName ) ; Assert . Equal ( 123 , idBackingFieldOnDestination . GetValue ( deserialised ) ) ; }
Support properties to be replaced on future versions of the type and for the serialised data generated from that future version to be deserialised assemblies that
have older versions of the type - this will only work if the replaced properties continue to exist on the future version but as computed properties that return (and
set, if the type should be mutable) values derived from the new data AND if the computed properties have the [Deprecated] attribute on them.
Support properties to be replaced on future versions of the type and for the serialised data generated from that future version to be deserialised assemblies that have older versions of the type - this will only work if the replaced properties continue to exist on the future version but as computed properties that return ( and set if the type should be mutable ) values derived from the new data AND if the computed properties have the [ Deprecated ] attribute on them .
// In a real world scenario, the "future type" would have other properties and the [Deprecated] one(s) would have values computed from them.. for the interests of this // unit test, the future type (typeWithDeprecatedProperty) will ONLY have a [Deprecated] property that has a "computed value" (ie. a getter that always returns 123) // For the sake of this test, the type that will be deserialised to only needs to have a backing field for an auto property (the field that we're expecting to // get set) and so that's all that is being configured. It would be closer to a real use case if there was a property with a getter that used this backing field // but it wouldn't be used by this test and so it doesn't need to be created.