private static IEnumerable <T> _WeightedSearch <T>(IEnumerable <T> collection, string searchCriteria, string languageCode, bool removeItemsWithoutMatch = true) { #region Validations - validate parameter and collection items type if (collection == null) { throw new Exception("Passed value cannot be null."); } if (string.IsNullOrEmpty(searchCriteria)) { return(collection); } if (!typeof(T).GetProperties().Any(x => x.CustomAttributes != null && x.CustomAttributes.Any(attribute => attribute.AttributeType == typeof(SearchWeight)))) { throw new Exception("Collection type doesn't have any property designated for search."); } if (!typeof(T).GetProperties().Any(x => x.CustomAttributes != null && x.CustomAttributes.Any(attribute => attribute.AttributeType == typeof(WeightedSearchValue)))) { throw new Exception("Collection type doesn't have a property designated for search result value."); } #endregion Validations - validate parameter and collection items type var propertiesForSearch = typeof(T).GetProperties().Where(x => x.CustomAttributes.Any(a => a.AttributeType == typeof(SearchWeight))).ToDictionary(x => x, x => ((SearchWeight)x.GetCustomAttributes(false).First(i => i is SearchWeight)).Weight); var propertyWithMatchingValue = typeof(T).GetProperties().First(x => x.CustomAttributes.Any(a => a.AttributeType == typeof(WeightedSearchValue))); var propertyWithNestedObject = typeof(T).GetProperties().FirstOrDefault(x => x.CustomAttributes.Any(a => a.AttributeType == typeof(SearchWeightNestedObject))); var searchTokens = searchCriteria.Trim().Contains(' ') ? searchCriteria.Trim().Split(' ') : new string[1] { searchCriteria.Trim() }; var culture = Thread.CurrentThread.CurrentUICulture; if (!string.IsNullOrEmpty(languageCode)) { culture = CultureInfo.GetCultures(CultureTypes.AllCultures).FirstOrDefault(x => x.Name.EndsWith("-" + languageCode.ToUpper())); } foreach (var item in collection) { var sum = _CalculateItemMatchingValue(item, propertiesForSearch, searchTokens, culture); // advanced - search through object tree if (propertyWithNestedObject != null && propertyWithNestedObject.GetValue(item) != null) { var resultingObject = new MatchingValueObject(); _CalculateChildrenMatchingValue((IEnumerable <T>)propertyWithNestedObject.GetValue(item), searchTokens, propertiesForSearch, propertyWithNestedObject, resultingObject, culture); sum += resultingObject.MatchingSum; } propertyWithMatchingValue.SetValue(item, sum); } if (removeItemsWithoutMatch) { var returnValue = collection.Where(x => (double)propertyWithMatchingValue.GetValue(x) > 0).OrderByDescending(x => (double)propertyWithMatchingValue.GetValue(x)); return(returnValue); } else { return(collection); } }
private static void _CalculateChildrenMatchingValue <T>(IEnumerable <T> childItems, string[] searchTokens, Dictionary <PropertyInfo, double> propertiesForSearch, PropertyInfo propertyWithNestedObject, MatchingValueObject resultObject, CultureInfo culture) { if (childItems != null && childItems.Any()) { foreach (var item in childItems) { resultObject.MatchingSum += _CalculateItemMatchingValue(item, propertiesForSearch, searchTokens, culture); if (propertyWithNestedObject.GetValue(item) != null) { _CalculateChildrenMatchingValue((IEnumerable <T>)propertyWithNestedObject.GetValue(item), searchTokens, propertiesForSearch, propertyWithNestedObject, resultObject, culture); } } } }