private static bool TryCreateNewObject(Type outputType, IReadOnlyDictionary <string, object> values, out object newObject) { // Create a default instance if one such constructor exists var contract = new ObjectContract(outputType); // TODO: Change this to some sort of factory for caching if (contract.HasDefaultConstructor) { newObject = contract.DefaultConstructor.Invoke(null); return(true); } if (contract.ParameterizedConstructor != null) { var parameters = contract.ParameterizedConstructor.GetParameters(); var orderedProperties = values.Where(v => parameters.Any(p => p.Name.Equals(v.Key, StringComparison.InvariantCultureIgnoreCase))) .OrderBy(v => parameters.IndexOf(parameters.First(p => p.Name.Equals(v.Key, StringComparison.InvariantCultureIgnoreCase)))) .Select(kv => kv.Value); newObject = contract.ParameterizedConstructor.Invoke(orderedProperties.ToArray()); return(true); } newObject = null; return(false); }
public object CreateNewObject(BitStreamReader reader, ObjectContract objectContract, DsdlProperty containerMember, DsdlProperty containerProperty, out bool createdFromNonDefaultCreator) { object newObject = null; if (objectContract.DefaultCreator != null && !objectContract.DefaultCreatorNonPublic) { // use the default constructor if it is... // public // non-public and the user has change constructor handling settings // non-public and there is no other creator newObject = objectContract.DefaultCreator(); } if (newObject == null) { if (!objectContract.IsInstantiable) { throw new SerializationException("Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType)); } throw new SerializationException("Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType)); } createdFromNonDefaultCreator = false; return(newObject); }
private bool ShouldSetPropertyValue(DsdlProperty property, ObjectContract contract, object value) { if (!property.Writable) { return(false); } return(true); }
void SerializeObject(BitStreamWriter writer, object value, ObjectContract contract, DsdlType derivedDsdlType, bool tailArrayOptimization) { var dsdlScheme = GetScheme <CompositeDsdlTypeBase>(contract, derivedDsdlType); _serializeStack.Push(value); SerializeObjectCore( writer, name => ResolveObjectProperty(value, contract, name), contract, derivedDsdlType, tailArrayOptimization); _serializeStack.Pop(); }
ResolvedProperty?ResolveObjectProperty(object value, ObjectContract contract, string name) { var property = contract.Properties.GetProperty(name, StringComparison.Ordinal); if (property == null) { return(null); } if (!CalculatePropertyValues(value, contract, property, out var memberContract, out var memberValue)) { return(null); } return(new ResolvedProperty { Member = property, MemberContact = memberContract, MemberValue = memberValue }); }
private object PopulateObject( object newObject, BitStreamReader reader, ObjectContract contract, DsdlProperty member, CompositeDsdlTypeBase scheme, bool tailArrayOptimization) { foreach (var(field, tao) in EnumerateSchemeFields(reader, scheme, tailArrayOptimization)) { if (field.Type is VoidDsdlType t) { ReadAlignment(reader, t); continue; } // attempt exact case match first // then try match ignoring case DsdlProperty property = contract.Properties.GetClosestMatchProperty(field.Name); if (property == null) { throw new SerializationException($"Could not find member '{field.Name}' on object of type '{contract.UnderlyingType.FullName}'"); } if (property.PropertyContract == null) { property.PropertyContract = GetContractSafe(property.PropertyType); } SetPropertyValue(property, contract, member, reader, newObject, field.Type, tao); } return(newObject); }
/// <summary> /// Binds the specified input string to an output object of a certain type. /// The value <paramref name="context" /> must be provided for performance reasons, as to avoid parsing the HTML tree multiple times. /// </summary> /// <param name="input">The input string. See <see cref="BindingBehavior" /> for examples on what types of information may be passed in.</param> /// <param name="context">The context of the currently being-bound input value. Generally the HTML element corresponding to the input value.</param> /// <param name="outputType">The type of output object to generate, whether a POCO, primitive, or other.</param> /// <param name="attribute">The optional attribute decorating the property that is currently being handled.</param> /// <returns> /// The output type object created, and filled with the parsed version of the <paramref name="input" />. /// </returns> public object Handle(string input, CQ context, Type outputType, BaseHtmlAttribute attribute) { if (context == null && input == null) { throw new ArgumentNullException(nameof(input), new ArgumentNullException(nameof(context))); } if (outputType == null) { throw new ArgumentNullException(nameof(outputType)); } if (context == null) { context = new CQ(input); } var contract = new ObjectContract(outputType); var allProperties = outputType.GetProperties(); var properties = allProperties.Where(p => p.CanWrite) .Union( allProperties.Where(p => contract.Parameters.Any( param => param.Name.Equals(p.Name, StringComparison.InvariantCultureIgnoreCase)))); // Changing this from setting to creating a hash table of values var values = properties.ToDictionary(property => property.Name, property => { var propertyAttribute = property.GetCustomAttributes(typeof(BaseHtmlAttribute), true).FirstOrDefault() as BaseHtmlAttribute; if (propertyAttribute != null) { var enumerableInterface = property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable <>) ? property.PropertyType : property.PropertyType.GetInterfaces() .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>)); var isEnumerable = enumerableInterface != null && property.PropertyType != typeof(string); // Find var typeOfFinder = isEnumerable ? typeof(IEnumerable <CQ>) : typeof(CQ); var nodeForProperty = FinderFactory.Instance.GetFinder(typeOfFinder) .Find(context, propertyAttribute.Selector); // Verify if (nodeForProperty != null) { object value; var nodes = nodeForProperty as IEnumerable <CQ>; var singleNode = nodeForProperty as CQ; if (nodes != null && isEnumerable) { value = BinderFactory.Instance.GetEnumerableBinder().Handle(nodes, property.PropertyType, propertyAttribute); } else if (singleNode != null) { // Single case value = ParseAndBind(propertyAttribute, property.PropertyType, singleNode); } else { throw new NapBindingException($"Unknown finder type found: {nodeForProperty.GetType().FullName}"); } return(value); } } // Return default type otherwise return(property.PropertyType.IsValueType ? Activator.CreateInstance(property.PropertyType) : null); }); // Construct using a greedy constructor mechanis object toReturn; if (TryCreateNewObject(outputType, values, out toReturn)) { foreach (var value in values) { // TODO: Add contract.Properties to cache PropertyInfos var pi = outputType.GetProperties(BindingFlags.Instance | BindingFlags.Public) .FirstOrDefault(p => p.Name.Equals(value.Key, StringComparison.InvariantCultureIgnoreCase)); if (pi?.CanWrite ?? false) { pi.SetValue(toReturn, value.Value); } } } return(toReturn); }