Question

Below is an example of a class that, searches an item in a DataGrid for text matches in it's property values. I currently call it with:

FullTextSearchNext<UserViewModel>.FullTextSearchInit();

The <UserViewModel> hardcoded above is what the ItemsSource in my DataGrid consists of. To clarify: the collection is made up of UserViewModel items.

What I am wondering is, is there a way I can get the item class (UserViewModel) from the DataGrid and replace the hardcoded <UserViewModel> with a variable of some sort? Thus making my calls to the ClassPropertySearch generic as well as the class itself.

public static class ClassPropertySearch<T>
{

    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;
    }

    private static List<Func<T, string>> _properties;

    public static void FullTextSearchInit()
    {
        _properties = GetPropertyFunctions().ToList();
    }
}

[EDIT] This is to show more of the class, which I should have done initially.
Includes Marius'solution:
Now that <T> is removed from ClassPropertySearch the other functions such as GetPropertyFunctions, etc, do not work , should I just pass the type through to them as parameters?

public static class ClassPropertySearch
{

    public static bool Match(Type itemType, string searchTerm)
    {
        bool match = _properties.Select(prop => prop(itemType)).Any(value => value != null && value.ToLower().Contains(searchTerm.ToLower()));
        return match;
    }

    private static List<Func<Type, string>> _properties;

    public static void FullTextSearchInit(List<string> binding_properties)
    {
        _properties = GetPropertyFunctions().ToList();
    }

    public static IEnumerable<Func<Type, string>> GetPropertyFunctions()
    {
        return GetStringPropertyFunctions();
    }

    public static IEnumerable<Func<Type, string>> GetStringPropertyFunctions()
    {
        var propertyInfos = typeof(Type).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<Type, string> GetStringPropertyFunc(PropertyInfo propInfo)
    {
        ParameterExpression x = System.Linq.Expressions.Expression.Parameter(typeof(Type), "x");
        Expression<Func<Type, string>> expression = System.Linq.Expressions.Expression.Lambda<Func<Type, string>>(System.Linq.Expressions.Expression.Property(x, propInfo), x);
        Func<Type, string> propertyAccessor = expression.Compile();
        return propertyAccessor;
    }
}
Was it helpful?

Solution

You could replace the generic type T with type Type.

public static class ClassPropertySearch
{
    public static bool Match(Type itemType, string searchTerm)
    {
        bool match = _properties.Select(prop => prop(itemType)).Any(value => value != null && value.ToLower().Contains(searchTerm.ToLower()));
        return match;
    }

    private static List<Func<Type, string>> _properties;

    public static void FullTextSearchInit()
    {
        _properties = GetPropertyFunctions().ToList();
    }
}

So instead of passing the UserViewModel you would pass typeof(UserViewModel). Of course, since you need this at runtime, you need to say obj.GetType().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top