protected SerializationInfo(Type objType, IFormatterConverter converter) { Type = objType; Converter = converter; // create an instance of the object to get missing values from the field initializers. object instance = STDFFormatterServices.GetUninitializedObject(Type); FieldInfo[] fields = STDFFormatterServices.GetSerializeableFields(Type); Info = new SerializationInfoEntry[fields.Length]; for (int i = 0; i < fields.Length; i++) { var field = fields[i]; object value = field.GetValue(instance); string itemCountField = (field.GetCustomAttribute <STDFAttribute>() ?? field.GetCustomAttribute <STDFOptionalAttribute>())?.ItemCountProperty; var entry = new SerializationInfoEntry() { Index = i, Name = field.Name, Type = field.FieldType, IsOptional = field.GetCustomAttribute <STDFOptionalAttribute>() != null, IsSet = false, ItemCountIndex = Array.FindIndex(fields, x => x.Name == itemCountField), Value = value, MissingValue = value }; Info[i] = entry; } }
protected virtual void SerializeValue(int index, object currentValue, object originalValue = null) { SerializationInfoEntry entry = CurrentInfo.GetEntry(index); object missingValue = entry.MissingValue; object defaultValue = CurrentDefaults?.GetValue(index); // if field is not an optional field, then no further checking required, // just return the value as is if (entry.IsOptional) { // logic to determine what value to serialize // // Truth table: // // OM = Original = missing value // DV = Current = default value // MV = Current = missing value // // O D M // M V V Action // - - - ----------------------------------- // 0 0 0 Write current value // 0 0 1 Write missing value // 0 1 0 Write current value // 0 1 1 Write missing value // 1 0 0 Write current value // 1 0 1 Write missing value // 1 1 0 Write missing value // 1 1 1 Write missing value int writeFlag = 0b000; writeFlag |= IsEqual(originalValue, missingValue) ? 0b100 : 0b000; writeFlag |= IsEqual(currentValue, defaultValue) ? 0b010 : 0b000; writeFlag |= IsEqual(currentValue, missingValue) ? 0b001 : 0b000; switch (writeFlag) { case 0b000: // original value != missing && current value (!= default && != missing) case 0b010: // original value != missing && current value (== default && != missing) case 0b100: // original value == missing) && current value (!= default && != missing) entry.Value = currentValue; entry.IsMissingValue = false; break; default: // all other combinations, return the missing value. entry.Value = missingValue; entry.IsMissingValue = true; break; } } else { entry.Value = currentValue; entry.IsMissingValue = IsEqual(currentValue, missingValue); } }
protected virtual object DeserializeValue(int index) { SerializationInfoEntry entry = CurrentInfo.GetEntry(index); object currentValue = entry.Value; object missingValue = entry.MissingValue; object defaultValue = CurrentDefaults?.GetValue(index); // if field is not an optional field, then no further checking required, // just return the value as read from the instream (or initialized with missing value) if (entry.IsOptional) { // logic to determine which value to deserialize to (as read, missing, or default value) // // Truth table: // // NV = Value is null // MV = Value is missing value // DV = Value is default value // // N M D // V V V Action // - - - ----------------------------------- // 0 0 0 Return value as read // 0 0 1 Return value as read // 0 1 0 Return default value // 0 1 1 Return default value // 1 0 0 Return value as read // 1 0 1 Return value as read // 1 1 0 Return default value // 1 1 1 Return default value int writeFlag = currentValue == null ? 0b100 : 0b000; writeFlag |= IsEqual(currentValue, missingValue) ? 0b010 : 0b000; writeFlag |= IsEqual(currentValue, defaultValue) ? 0b001 : 0b000; switch (writeFlag) { case 0b000: // as read value (!= null && != missing && != default) case 0b001: // as read value (!= null && != missing && == default) case 0b100: // as read value (== null && != missing && != default) case 0b101: // as read value (== null && != missing && == default) return(currentValue); default: // all other combinations, return the default value. return(defaultValue); } } return(currentValue); }