private static SerializableMember Create(TypeInfo beingSerializedType, string name, MethodInfo getter, FieldInfo field, MethodInfo formatter, MethodInfo shouldSerialize, bool emitDefaultValue) { if (beingSerializedType == null) { Throw.ArgumentNullException(nameof(beingSerializedType)); } if (name == null) { Throw.ArgumentNullException(nameof(name)); } if (field == null && getter == null) { Throw.InvalidOperationException($"At least one of {nameof(field)} and {nameof(getter)} must be non-null"); } if (field != null && getter != null) { Throw.InvalidOperationException($"Only one of {nameof(field)} and {nameof(getter)} can be non-null"); } if (formatter == null) { Throw.ArgumentNullException(nameof(formatter)); } TypeInfo toSerializeType; // getter can be an instance method or a static method // if it's a static method, it can take 0 or 1 parameters // the 1 parameter must be the type to be serialized, or something it is assignable to // if it's an instance method, it can only take 0 parameters if (getter != null) { if (getter.ReturnType == Types.VoidType) { Throw.ArgumentException($"{nameof(getter)} must return a non-void value", nameof(getter)); } var getterParams = getter.GetParameters(); if (getter.IsStatic) { if (getterParams.Length == 0) { /* that's fine */ } else if (getterParams.Length == 1) { var takenParam = getterParams[0].ParameterType.GetTypeInfo(); if (!takenParam.IsAssignableFrom(beingSerializedType)) { Throw.ArgumentException($"{getter}'s single parameter must be assignable from {beingSerializedType}", nameof(getter)); } } else { Throw.ArgumentException($"Since {getter} is a static method, it cannot take more than 1 parameter", nameof(getter)); } } else { if (getterParams.Length > 0) { Throw.ArgumentException($"Since {getter} is an instance method, it cannot take any parameters", nameof(getter)); } } toSerializeType = getter.ReturnType.GetTypeInfo(); } else { toSerializeType = field.FieldType.GetTypeInfo(); } // formatter needs to take the toSerializeType (or a type it's assignable to) // and an IBufferWriter<char> // and a WriteContext // and return bool (false indicates insufficient space was available) { if (!formatter.IsStatic) { Throw.ArgumentException($"{nameof(formatter)} must be a static method", nameof(formatter)); } var formatterRetType = formatter.ReturnType.GetTypeInfo(); if (formatterRetType != Types.BoolType) { Throw.ArgumentException($"{nameof(formatter)} must return bool", nameof(formatter)); } var args = formatter.GetParameters(); if (args.Length != 3) { Throw.ArgumentException($"{nameof(formatter)} must take 3 parameters", nameof(formatter)); } if (!args[0].ParameterType.IsAssignableFrom(toSerializeType)) { Throw.ArgumentException($"The first paramater to {nameof(formatter)} must be accept a {toSerializeType}", nameof(formatter)); } var p2 = args[1].ParameterType.GetTypeInfo(); if (!p2.IsByRef) { Throw.ArgumentException($"The second paramater to {nameof(formatter)} must be an in {nameof(WriteContext)}, was not by ref", nameof(formatter)); } if (p2.GetElementType() != Types.WriteContext) { Throw.ArgumentException($"The second paramater to {nameof(formatter)} must be an in {nameof(WriteContext)}", nameof(formatter)); } if (args[2].ParameterType.GetTypeInfo() != Types.IBufferWriterOfCharType) { Throw.ArgumentException($"The third paramater to {nameof(formatter)} must be a {nameof(IBufferWriter<char>)}", nameof(formatter)); } } var shouldSerializeOnType = (getter?.DeclaringType ?? field?.DeclaringType).GetTypeInfo(); CheckShouldSerializeMethod(shouldSerialize, shouldSerializeOnType); return(new SerializableMember(name, getter, field, formatter, shouldSerialize, emitDefaultValue)); }
private static DeserializableMember Create(TypeInfo beingDeserializedType, string name, MethodInfo setter, FieldInfo field, MethodInfo parser, bool isRequired, MethodInfo reset) { if (beingDeserializedType == null) { Throw.ArgumentNullException(nameof(beingDeserializedType)); } if (name == null) { Throw.ArgumentNullException(nameof(name)); } if (field == null && setter == null) { Throw.InvalidOperationException($"At least one of {nameof(field)} and {nameof(setter)} must be non-null"); } if (field != null && setter != null) { Throw.InvalidOperationException($"Only one of {nameof(field)} and {nameof(setter)} can be non-null"); } if (parser == null) { Throw.ArgumentNullException(nameof(parser)); } if (name.Length == 0) { Throw.ArgumentException($"{nameof(name)} must be at least 1 character long", nameof(name)); } TypeInfo valueType; // setter must take single parameter (the result of parser) // can be instance or static // and cannot return a value // -- OR -- // setter must take two parameters, // the first is the record value // the second is the value (the result of parser) // cannot return a value // and must be static if (setter != null) { var args = setter.GetParameters(); if (args.Length == 1) { valueType = args[0].ParameterType.GetTypeInfo(); var returnsNoValue = setter.ReturnType == Types.VoidType; if (!returnsNoValue) { Throw.ArgumentException($"{nameof(setter)} must not return a value", nameof(setter)); } } else if (args.Length == 2) { valueType = args[1].ParameterType.GetTypeInfo(); var returnsNoValue = setter.ReturnType == Types.VoidType; if (!returnsNoValue) { Throw.ArgumentException($"{nameof(setter)} must not return a value", nameof(setter)); } if (!setter.IsStatic) { Throw.ArgumentException($"{nameof(setter)} taking two parameters must be static", nameof(setter)); } } else { Throw.ArgumentException($"{nameof(setter)} must take one or two parameters", nameof(setter)); return(default); // just for flow control, the above won't actually return