以下代码用于搜索类对象的属性以进行文本匹配。
我称之为:
ClassPropertyTextSearchOrig<UserViewModel>.FullTextSearchInit();
if (FullTextSearch<UserViewModel>.Match((UserViewModel)item, searchValue))
{
matchedItems.Add(item);
}
类属性搜索:
public static class ClassPropTextSearch<T>
{
private static List<Func<T, string>> _properties;
public static void FullTextSearchInit()
{
_properties = GetPropertyFunctions().ToList();
}
public static IEnumerable<Func<T, string>> GetPropertyFunctions()
{
var stringProperties = GetStringPropertyFunctions();
return stringProperties;
}
public static IEnumerable<Func<T, string>> GetStringPropertyFunctions()
{
var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)
.Where(p => p.PropertyType == typeof(string)).ToList();
var properties = propertyInfos.Select(GetStringPropertyFunc);
return properties;
}
public static Func<T, string> GetStringPropertyFunc(PropertyInfo propInfo)
{
ParameterExpression x = System.Linq.Expressions.Expression.Parameter(typeof(T), "x");
Expression<Func<T, string>> expression = System.Linq.Expressions.Expression.Lambda<Func<T, string>>(System.Linq.Expressions.Expression.Property(x, propInfo), x);
Func<T, string> propertyAccessor = expression.Compile();
return propertyAccessor;
}
public static bool Match(T item, string searchTerm)
{
bool match = _properties.Select(prop => prop(item)).Any(value => value != null && value.ToLower().Contains(searchTerm.ToLower()));
return match;
}
}
我想做的是让它更具动态性,这样我就可以传递对象的Type,而不是对对象T进行硬编码。
摆脱T并传递Type,很好。但如果我这样做,有人可以帮助我创建一个有效的过程。这可能有数万个对象要迭代。关于如何开始,我有点失落。我还可以通过初始化一些来节省时间吗?
[编辑]
这段代码显示了如何获取绑定到DataGrid中列的属性名称列表。每次进行搜索时都会执行此操作,因为列顺序可能会更改。
string binding_path = "";
var columnBoundProperties = new List<KeyValuePair<int, string>>();
//Gets list of column bound properties and their display index
foreach (var col in datagrid.Columns.Where(c => c.Visibility == System.Windows.Visibility.Visible))
{
var binding = (col as DataGridBoundColumn).Binding as Binding;
binding_path = binding.Path.Path;
columnBoundProperties.Add(new KeyValuePair<int, string>(col.DisplayIndex, binding.Path.Path));
}
ClassPropTextSearch.Init(datagrid.Items[0].GetType(), columnBoundProperties)
var itemsSource = datagrid.Items as IEnumerable;
foreach (var item in itemsSource)
{
int column_index_match = ClassPropTextSearch.FirstPropMatch(item, searchValue);
if (column_index_match != null)
{
//Do something
break;
}
//else continue searching items
}
就对象搜索而言,我仍然希望保持初始化方面的东西,所以这里是
的模型public static class ClassPropTextSearch
{
private static Type _itemType;
private static List<KeyValuePair<int, PropertyInfo>> _stringProperties = new List<KeyValuePair<int, PropertyInfo>>();
public static void init(Type itemType, List<KeyValuePair<int, string>> binding_properties)
{
_itemType = itemType;
foreach (var prop in binding_properties)
{
PropertyInfo propertyInfo = _itemType.GetProperty(prop.Value);
if (propertyInfo != null)
{
if (propertyInfo.PropertyType == typeof(string))
{
_stringProperties.Add(new KeyValuePair<int, PropertyInfo>(prop.Key, propertyInfo));
}
}
}
}
public static bool Match(object item, string searchTerm)
{
return PropertiesMatch(item, searchTerm).Any();
}
public static string FirstPropMatch(object item, string searchTerm)
{
//return int index of first property match
}
private static IEnumerable<PropertyInfo> PropertiesMatch(object item, string searchTerm)
{
//return list of matches
}
}
答案 0 :(得分:1)
透明地完成所有工作。
不要通过Type
- 只需传递您要调查的object
即可。您可以致电Type
来获取GetType()
。
然后,在你的助手类(进行搜索的那个)中有一个单Dictionary
(或ConcurrentDictionary
),它会将类的Type
键入你的类创建。你的类看起来像这样(并且将是不可变的):
class StringProps
{
PropertyInfo[] m_infos;
}
所以现在你有一个StringPropertyInfo []列表,你创建的代码与你的代码相同。 (如果您的Dictionary中缺少StringProps,您只需创建它并添加它)。这样你就可以缓存所有属性的版本,你可以使用它们从对象中获取相关的文本字符串。
一些注意事项:
System.Linq.Expressions
和特别是System.Linq.Expressions.LambdaExpression
来完成,这将允许您创建一个委托,该委托接受一个对象并将其转换为正确的类型,调用正确的属性(因此不会通过反射)。 答案 1 :(得分:1)
尝试以下版本,主要更改:
public static class ClassPropTextSearch
{
private static Dictionary<Type, List<PropertyInfo>> _stringProperties =
new Dictionary<Type, List<PropertyInfo>>();
public static bool Match(object item, string searchTerm)
{
return PropertiesMatch(item, searchTerm).Any();
}
public static string FirstPropMatch(object item, string searchTerm)
{
var prop = PropertiesMatch(item, searchTerm).FirstOrDefault();
return prop != null ? prop.Name : string.Empty;
}
private static IEnumerable<PropertyInfo> PropertiesMatch(object item, string searchTerm)
{
// null checking skipped...
if (!_stringProperties.ContainsKey(item.GetType()))
{
// Retrieve and store the list of string properties of the input's type
var stringProperties = item.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)
.Where(p => p.PropertyType == typeof(string))
.ToList();
_stringProperties.Add(item.GetType(), stringProperties);
}
return _stringProperties[item.GetType()]
.Where(prop => prop.GetValue(item, null) != null &&
((string)prop.GetValue(item, null)).ToLower().Contains(searchTerm.ToLower()));
}
}
现在使用简化为:
if (ClassPropTextSearch.Match(item, searchValue))
{
matchedItems.Add(item);
}