如何运行类型为的LINQ查询< T>

siotufzp  于 2022-12-06  发布在  其他
关注(0)|答案(3)|浏览(141)

这是我的类,基本上是闭耦合的,我想把这个类泛化。
所以我可以用所有的类
调用此方法时有一个Name字段是常见的

public class CustomSuggestionProvider : ISuggestionProvider
    {
        private const int batchSize = 30;
        private string _criteria = string.Empty;
        private int _skipCount;

        private readonly ObservableCollection<LanguageItem> _observableCollection;
        private readonly List<LanguageItem> _source;

        public CustomSuggestionProvider(ObservableCollection<LanguageItem> observableCollection, List<LanguageItem> source)
        {
            _observableCollection = observableCollection;
            _source = source;
        }

        public bool HasMoreSuggestions { get; private set; } = true;

        public Task<IList<object>> GetSuggestionsAsync(string criteria, CancellationToken cancellationToken)
        {
            _criteria = criteria;
            var newItems = _source.Where(x => x.Name.IndexOf(_criteria, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
            if (cancellationToken.IsCancellationRequested)
                return null;
            HasMoreSuggestions = newItems.Count > batchSize;
            _skipCount = batchSize;
            return Task.FromResult<IList<object>>(newItems.Take(batchSize).Cast<object>().ToList());
        }

     
    }

我只是把它概括成这样。
使所有紧密耦合的类都变成T型。
请看一看。

public class CustomSuggestionProvider<T> :  ISuggestionProvider
    {
        private const int batchSize = 30;
        private string _criteria = string.Empty;
        private int _skipCount;
        
        private readonly ObservableCollection<T> _observableCollection;
        private readonly List<T> _source;

        public CustomSuggestionProvider(ObservableCollection<T> observableCollection, List<T> source)
        {
            _observableCollection = observableCollection;
            _source = source;
        }
 

        public bool HasMoreSuggestions { get; private set; } = true;
]

        public Task<IList<object>> GetSuggestionsAsync(string criteria, CancellationToken cancellationToken)
        {
            _criteria = criteria;
                var newItems = _source.Where(x =>Name.IndexOf(_criteria, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
            if (cancellationToken.IsCancellationRequested)
                return null;
            HasMoreSuggestions = newItems.Count > batchSize;
            _skipCount = batchSize;
            return Task.FromResult<IList<object>>(newItems.Take(batchSize).Cast<object>().ToList());
        }

        public Task<IList<object>> GetSuggestionsAsync(CancellationToken cancellationToken)
        {
            var newItems = _source.Where(x => x.Name.StartsWith(_criteria)).Skip(_skipCount).ToList();
            if (cancellationToken.IsCancellationRequested)
                return null;
            HasMoreSuggestions = newItems.Count > batchSize;
            _skipCount += batchSize;
            return Task.FromResult<IList<object>>(newItems.Take(batchSize).Where(x => !_observableCollection.Any(y => y.Id == x.Id)).Cast<object>().ToList());
        }
    }

我刚说到这里就卡住了
此处不存在'Name'

var newItems = _source.Where(x => x.Name.IndexOf(_criteria, StringComparison.OrdinalIgnoreCase) >= 0).ToList();

你能帮忙解决这个问题吗?
提前致谢。

dpiehjr4

dpiehjr41#

您有两个选择。第一-对象必须继承包含Name属性的接口/类。第二,您可以使用反射并通过编译的lambda访问Name属性

List<ObjectWithName> items = new List<ObjectWithName>()
    {
        new ObjectWithName { Name = "Hello World #1"},
        new ObjectWithName { Name = "Hello World #2"}
    };

    var result = FirstOption(items, "Hello");
    result = SecondOption(items, "Hello");
    ...

    public static List<T> FirstOption<T>(IList<T> source, string criteria) where T: IObjectWithName
    {
        return source.Where(t => t.Name.IndexOf(criteria, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
    }

    public static List<T> SecondOption<T>(IList<T> source, string criteria)
    {
        PropertyInfo propertyInfo = typeof(T).GetProperty("Name");
        MethodInfo getterMethodInfo = propertyInfo.GetGetMethod();
        ParameterExpression entity = Expression.Parameter(typeof(T));
        MethodCallExpression getterCall = Expression.Call(entity, getterMethodInfo);
        UnaryExpression castToObject = Expression.Convert(getterCall, typeof(string));
        LambdaExpression lambda = Expression.Lambda(castToObject, entity);
        var functionThatGetsValue = (Func<T, string>)lambda.Compile();

        return source.Where(t => functionThatGetsValue(t).IndexOf(criteria, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
    }
}

public class ObjectWithName: IObjectWithName
{
    public string Name { get; set; }
}

public interface IObjectWithName
{
    string Name { get; }
}

为了进行优化,只能为类型编译一次lambda并缓存结果

ktecyv1j

ktecyv1j2#

你应该写一个这样的接口

public interface IName
{
    string Name { set; get; }
}

注意:所有类都应从IName实现
编写如下函数

public static IList<IName> Names(IList<IName> names, string _criteria)
{
    return names.Where(c => c.Name.IndexOf(_criteria, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
}

而这是IEnumerable的扩展方法

public static class IEnumerableExtension
{
    public static IEnumerable<IName> Filter(this IEnumerable<IName> names, string _criteria)
    {
        return names.Where(c => c.Name.IndexOf(_criteria, StringComparison.OrdinalIgnoreCase) >= 0);
    }
}
bfnvny8b

bfnvny8b3#

在我看来,比"需要IName接口"或"使用反射"选项更好的是:当构造CustomSuggestionProvider<T>时,传入Func<T, string>,每当提供者需要T的名称时,提供者可以调用Func<T, string>
CustomSuggestionProvider<T>中添加

Func<T, string> nameGetter;

在构造函数中初始化它,调用方传入类似于class => class.Name的内容。
然后每当你需要一个T的名字时,你只需调用这个函数。

var newItems = _source
    .Where(x => x.Name.IndexOf(_criteria, StringComparison.OrdinalIgnoreCase) >= 0)
    .ToList();

变成

var newItems = _source
    .Where(x => nameGetter(x).IndexOf(_criteria, StringComparison.OrdinalIgnoreCase) >= 0)
    .ToList();

相关问题