/// <summary> /// Default key serializer /// </summary> byte[] IBigtableKeySerializer <object> .SerializeKey(object instance, Encoding encoding) { // Contract if (instance == null) { throw new InvalidOperationException("Can not serialize keys on a null reference."); } // Locals //bool missingKey = false; var bytes = new List <byte[]>(); var separator = encoding.GetBytes(KeyFieldSeparator); // Iterate keys for (int index = 0; index < KeyFields.Length; index++) { // Localize var fieldName = KeyFields[index]; var required = RequiredFields.Contains(fieldName); var value = Getters[fieldName](instance); // if (value == null) { if (required) { throw new SerializationException(String.Format("The member {0} on type {1} is marked as required but was not specified", FieldNameLookup[fieldName], _type)); } bytes.Add(separator); //missingKey = true; continue; } //if (missingKey) //{ // // Programmer exception // var exception = new MissingFieldException(_type.Name, memberName); // // User exception // TODO: I think I designed around this // throw new SerializationException("The default serializer insists that the primary keys are filled in order. Missing keys are okay as long as all subsequent keys are missing as well.", exception); //} var valueType = value.GetType(); var serializer = GetSerializerForType(valueType); if (IsBigBoxed[fieldName]) { if (!IsSpecified[fieldName](instance)) { bytes.Add(new byte[0]); continue; } //var fieldType = MemberTypes[memberName]; //var access = GetKeyAccess(fieldType); //value = access.ValueGetter(value); } var serialized = serializer.SerializeField(valueType, value, TableEncoding); bytes.Add(serialized); } var bytesSize = bytes.Count - 1; var sepLength = (bytesSize) * separator.Length; var results = new byte[sepLength + bytes.Sum(b => b.Length)]; var ptr = 0; for (int index = 0; index < bytes.Count; index++) { // Get field bytes var source = bytes[index]; // Copy to result array in correct position Array.Copy(source, 0, results, ptr, source.Length); // Move ptr forward ptr += source.Length; if (index < bytesSize) { // Copy in separator Array.Copy(separator, 0, results, ptr, sepLength); // Move ptr foward ptr += sepLength; } } // Tada! return(results); }
private bool ExtractAccessors(MemberInfo member, string fieldName, ref Type dataType, ref bool isKey) { // Locals var getter = default(FieldGetterDelegate); var setter = default(FieldSetterDelegate); // Homogenize fields and properties switch (member.MemberType) { case System.Reflection.MemberTypes.Field: var field = ((FieldInfo)member); dataType = field.FieldType; getter = field.GetValue; setter = field.SetValue; break; case System.Reflection.MemberTypes.Property: var property = ((PropertyInfo)member); dataType = property.PropertyType; getter = property.GetValue; setter = property.SetValue; break; default: // Ignore other member types return(false); } // Inspect fields for key, specifiable/actual data type var bigtableKey = member.GetCustomAttribute <BigTableKeyAttribute>(); var genDataType = dataType.IsGenericType ? dataType.GetGenericTypeDefinition() : null; var isBigField = genDataType == typeof(BigTableField <>); var isBigKey = genDataType == typeof(BigTableKey <>); isKey = bigtableKey != null || genDataType == typeof(BigTableKey <>); var isBigWrapper = isBigField || isBigKey; IsBigBoxed.Add(fieldName, isBigWrapper); // Store accessors if (isBigWrapper) { var subDataType = dataType.GenericTypeArguments[0]; var access = isKey ? (BigAccess)GetKeyAccess(subDataType) : GetFieldAccess(subDataType); IsSpecified.Add(fieldName, target => ((IBigTableField)getter(target)).IsSpecified); Getters.Add(fieldName, target => access.ValueGetter(getter(target))); var useDataType = dataType; Setters.Add(fieldName, (target, value) => { var newValue = Activator.CreateInstance(useDataType); access.ValueSetter(newValue, value); setter(target, newValue); }); dataType = subDataType; } else { IsSpecified.Add(fieldName, target => true); Getters.Add(fieldName, getter); Setters.Add(fieldName, setter); } // Indicate is property of field return(true); }