private static bool TryExtractCurrentChildPropertyInfo([NotNull] object model, [NotNull] string pathPart, out PropertyInfo childPropertyInfo) { var propertyName = TemplateDescriptionHelper.GetPathPartName(pathPart); childPropertyInfo = model.GetType().GetProperty(propertyName); return(childPropertyInfo != null); }
private static List <Expression> BuildExtractionOfChildModelSetter([NotNull] Type currNodeType, [NotNull] Expression currNodeExpression, [NotNull] Expression valueToSetExpression, [NotNull, ItemNotNull] string[] pathParts) { var statements = new List <Expression>(); for (var partIndex = 0; partIndex < pathParts.Length; ++partIndex) { var name = TemplateDescriptionHelper.GetPathPartName(pathParts[partIndex]); var newNodeType = currNodeType.GetProperty(name)?.PropertyType; currNodeType = newNodeType ?? throw new ObjectPropertyExtractionException($"Type '{currNodeType}' has no property '{name}'"); currNodeExpression = Expression.Property(currNodeExpression, name); if (TemplateDescriptionHelper.IsCollectionAccessPathPart(pathParts[partIndex])) { List <Expression> statementsToAdd; (currNodeExpression, currNodeType, statementsToAdd) = BuildExpandingOfCollectionAccessPart(currNodeExpression, currNodeType, pathParts[partIndex]); statements.AddRange(statementsToAdd); } else if (TemplateDescriptionHelper.IsArrayPathPart(pathParts[partIndex])) { var statementsToAdd = BuildExpandingOfArrayPart(currNodeExpression, currNodeType, valueToSetExpression, pathParts.Skip(partIndex + 1).ToArray()); statements.AddRange(statementsToAdd); return(statements); } else if (!TypeCheckingHelper.IsNullable(currNodeType) && partIndex != pathParts.Length - 1) { statements.Add(ExpressionPrimitives.CreateValueInitStatement(currNodeExpression, currNodeType)); } } statements.Add(ExpressionPrimitives.AssignWithTypeCheckings(currNodeExpression, currNodeType, valueToSetExpression)); return(statements); }
private static PropertyInfo ExtractPropertyInfo([NotNull] Type type, [NotNull] string pathPart) { var propertyName = TemplateDescriptionHelper.GetPathPartName(pathPart); var childPropertyInfo = type.GetProperty(propertyName); if (childPropertyInfo == null) { throw new ObjectPropertyExtractionException($"Property with name '{propertyName}' not found in type '{type}'"); } return(childPropertyInfo); }
private ExcelTemplatePath(string rawPath) { if (!TemplateDescriptionHelper.IsCorrectModelPath(rawPath)) { throw new ObjectPropertyExtractionException($"Invalid excel template path '{rawPath}'"); } PartsWithIndexers = rawPath.Split('.'); PartsWithoutArrayAccess = PartsWithIndexers.Select(TemplateDescriptionHelper.GetArrayPathPartName).ToArray(); RawPath = rawPath; HasArrayAccess = PartsWithIndexers.Any(TemplateDescriptionHelper.IsArrayPathPart); HasPrimaryKeyArrayAccess = PartsWithIndexers.Any(TemplateDescriptionHelper.IsPrimaryArrayPathPart); }
public (ExcelTemplatePath pathToEnumerable, ExcelTemplatePath relativePathToItem) SplitForEnumerableExpansion() { if (!HasArrayAccess) { throw new BaseExcelSerializationException($"Expression needs enumerable expansion but has no part with '[]' or '[#]' (path - '{RawPath}')"); } var pathToEnumerableLength = PartsWithIndexers.TakeWhile(x => !TemplateDescriptionHelper.IsArrayPathPart(x)).Count() + 1; var pathToEnumerable = new ExcelTemplatePath(string.Join(".", PartsWithIndexers.Take(pathToEnumerableLength))); var relativePathToItem = new ExcelTemplatePath(string.Join(".", PartsWithIndexers.Skip(pathToEnumerableLength))); return(pathToEnumerable, relativePathToItem); }
public static ExcelTemplatePath FromRawExpression(string expression) { if (expression == null || !TemplateDescriptionHelper.IsCorrectAbstractValueDescription(expression)) { throw new ObjectPropertyExtractionException($"Invalid description '{expression}'"); } var parts = TemplateDescriptionHelper.GetDescriptionParts(expression); if (parts.Length != 3) { throw new ObjectPropertyExtractionException($"Invalid description '{expression}'"); } return(new ExcelTemplatePath(parts[2])); }
private static (bool succeed, object result) TryExtractChildObject([NotNull] object model, [NotNull, ItemNotNull] string[] pathParts, int pathPartIndex) { if (pathPartIndex == pathParts.Length) { return(true, model); } if (!TryExtractDirectChild(model, pathParts[pathPartIndex], out var currentChild)) { return(false, null); } if (currentChild == null) { return(true, null); } if (TemplateDescriptionHelper.IsArrayPathPart(pathParts[pathPartIndex])) { if (!TypeCheckingHelper.IsEnumerable(currentChild.GetType())) { throw new ObjectPropertyExtractionException($"Trying to extract enumerable from non-enumerable property {string.Join(".", pathParts)}"); } var resultList = new List <object>(); foreach (var element in ((IEnumerable)currentChild).Cast <object>()) { if (element == null) { resultList.Add(null); } else { var(succeed, result) = TryExtractChildObject(element, pathParts, pathPartIndex + 1); if (!succeed) { return(false, result); } resultList.Add(result); } } return(true, resultList.ToArray()); } return(TryExtractChildObject(currentChild, pathParts, pathPartIndex + 1)); }
public static Type ExtractChildObjectTypeFromPath([NotNull] Type modelType, [NotNull] ExcelTemplatePath path) { var currType = modelType; foreach (var part in path.PartsWithIndexers) { var childPropertyType = ExtractPropertyInfo(currType, part).PropertyType; if (TemplateDescriptionHelper.IsCollectionAccessPathPart(part)) { if (TypeCheckingHelper.IsDictionary(childPropertyType)) { var(keyType, valueType) = TypeCheckingHelper.GetDictionaryGenericTypeArguments(childPropertyType); TemplateDescriptionHelper.ParseCollectionIndexerOrThrow(TemplateDescriptionHelper.GetCollectionAccessPathPartIndex(part), keyType); currType = valueType; } else if (TypeCheckingHelper.IsIList(childPropertyType)) { TemplateDescriptionHelper.ParseCollectionIndexerOrThrow(TemplateDescriptionHelper.GetCollectionAccessPathPartIndex(part), typeof(int)); currType = TypeCheckingHelper.GetEnumerableItemType(childPropertyType); } else { throw new ObjectPropertyExtractionException($"Not supported collection type {childPropertyType}"); } } else if (TemplateDescriptionHelper.IsArrayPathPart(part)) { if (TypeCheckingHelper.IsIList(childPropertyType)) { currType = TypeCheckingHelper.GetIListItemType(childPropertyType); } else { throw new ObjectPropertyExtractionException($"Not supported collection type {childPropertyType}"); } } else { currType = childPropertyType; } } return(currType); }
private static bool TryExtractDirectChild([NotNull] object model, [NotNull] string pathPart, out object child) { child = null; if (TemplateDescriptionHelper.IsCollectionAccessPathPart(pathPart)) { var name = TemplateDescriptionHelper.GetCollectionAccessPathPartName(pathPart); var key = TemplateDescriptionHelper.GetCollectionAccessPathPartIndex(pathPart); if (!TryExtractCurrentChildPropertyInfo(model, name, out var collectionPropertyInfo)) { return(false); } if (TypeCheckingHelper.IsDictionary(collectionPropertyInfo.PropertyType)) { var indexer = TemplateDescriptionHelper.ParseCollectionIndexerOrThrow(key, TypeCheckingHelper.GetDictionaryGenericTypeArguments(collectionPropertyInfo.PropertyType).keyType); var dict = collectionPropertyInfo.GetValue(model, null); if (dict == null) { return(true); } child = ((IDictionary)dict)[indexer]; return(true); } if (TypeCheckingHelper.IsIList(collectionPropertyInfo.PropertyType)) { var indexer = (int)TemplateDescriptionHelper.ParseCollectionIndexerOrThrow(key, typeof(int)); var list = collectionPropertyInfo.GetValue(model, null); if (list == null) { return(true); } child = ((IList)list)[indexer]; return(true); } throw new ObjectPropertyExtractionException($"Unexpected child type: expected dictionary or array (pathPath='{pathPart}'), but model is '{collectionPropertyInfo.PropertyType}' in '{model.GetType()}'"); } if (!TryExtractCurrentChildPropertyInfo(model, pathPart, out var propertyInfo)) { return(false); } child = propertyInfo.GetValue(model, null); return(true); }
private static (Expression currNodeExpression, Type currNodeType, List <Expression> statements) BuildExpandingOfCollectionAccessPart([NotNull] Expression currNodeExpression, [NotNull] Type currNodeType, [NotNull] string part) { var statements = new List <Expression>(); if (TypeCheckingHelper.IsDictionary(currNodeType)) { statements.Add(ExpressionPrimitives.CreateValueInitStatement(currNodeExpression, currNodeType)); var(dictKeyType, dictValueType) = TypeCheckingHelper.GetDictionaryGenericTypeArguments(currNodeType); var indexer = TemplateDescriptionHelper.ParseCollectionIndexerOrThrow(TemplateDescriptionHelper.GetCollectionAccessPathPartIndex(part), dictKeyType); var dictElementExpression = Expression.Property(currNodeExpression, "Item", Expression.Constant(indexer)); statements.Add(ExpressionPrimitives.CreateDictValueInitStatement(currNodeExpression, dictKeyType, dictValueType, indexer)); currNodeExpression = dictElementExpression; currNodeType = dictValueType; } else if (currNodeType.IsArray) { var arrayItemType = currNodeType.GetElementType() ?? throw new ObjectPropertyExtractionException($"Array of type '{currNodeType}' has no item type"); var indexer = TemplateDescriptionHelper.ParseCollectionIndexerOrThrow(TemplateDescriptionHelper.GetCollectionAccessPathPartIndex(part), typeof(int)); statements.Add(ExpressionPrimitives.CreateArrayExtendStatement(currNodeExpression, Expression.Constant((int)indexer + 1), arrayItemType)); var arrayItemExpression = Expression.ArrayAccess(currNodeExpression, Expression.Constant(indexer)); currNodeExpression = arrayItemExpression; currNodeType = arrayItemType; statements.Add(ExpressionPrimitives.CreateValueInitStatement(currNodeExpression, currNodeType)); } else { throw new ObjectPropertyExtractionException("Only dicts and arrays are supported as collections"); } return(currNodeExpression, currNodeType, statements); }