【问题标题】:Make Linq function more generic parameters使 Linq 函数更通用的参数
【发布时间】:2019-12-26 01:48:12
【问题描述】:

如何概括这个函数?我希望Name 属性是可变的,并且有函数接受,用任何类替换persons 类。

// Filtering logic  
Func<SampleFilterModel, IEnumerable<Person>> filterData = (filterModel) =>  
{  
    return persons.Where(p => p.Name.StartsWith(filterModel.Term ?? String.Empty, StringComparison.InvariantCultureIgnoreCase))  
       .Skip((filterModel.Page-1) * filter.Limit)  
       .Take(filterModel.Limit);  
};  

其他项目:

IEnumerable<Person> persons = new List<Person>() {
    new Person() { Name = "Laura Callahan", DOB = DateTime.Parse("1958-01-09"), Email = "laura.callahan@test.com" },
    new Person() { Name = "Anne Dodsworth", DOB = DateTime.Parse("1966-01-27"), Email = "anne.dodsworth@test.com" }
};

public class SampleFilterModel
{
    public int Page { get; set; }
    public int Limit { get; set; }
    public string Term { get; set; }

    public SampleFilterModel()
    {
        this.Page = 1;
        this.Limit = 3;
    }

    public object Clone()
    {
        var jsonString = JsonConvert.SerializeObject(this);
        return JsonConvert.DeserializeObject(jsonString, this.GetType());
    }
}

当前尝试,根据需要尝试修改/返工:

给出一些问题/错误:

  1. 是否必须将所有变量声明为静态变量?

  2. 收到错误信息:

    “T”不包含“propertyInfo”的定义,并且找不到接受“T”类型的第一个参数的可访问扩展方法“propertyInfo”(您是否缺少 using 指令或程序集引用?)

代码:

public class Filterclass<T> where T : class
{
    public static string ColumnName;
    public static SampleFilterModel filter = new SampleFilterModel();
    public static IEnumerable<T> input;

    public Func<SampleFilterModel, IEnumerable<T>> filterData = (filterModel) =>
    {
        var propertyInfo = input.GetType().GetProperty(ColumnName);

        return input.Where(p => p.propertyInfo.StartsWith(filterModel.Term ?? String.Empty, StringComparison.InvariantCultureIgnoreCase))
        .Skip((filterModel.Page - 1) * filter.Limit)
        .Take(filterModel.Limit);
    };
}

【问题讨论】:

  • 嗨@VidmantasBlazevicius 试图弄清楚,不确定评论是否会增加价值,几个月前开始编程,对于提出问题的人来说,显示当前尝试meta.stackexchange.com/questions/223480/… 也是一个很好的做法,还是谢谢你
  • 阅读 linq 表达式树并动态构建 linq 表达式。
  • 除非您使用某种保证 Name 属性存在的合同,否则您将不得不使用反射和动态表达式。
  • 嗨@Nkosi 正确,尝试在这里实现它,var propertyInfo = input.GetType().GetProperty(ColumnName);
  • 您只是想从propertyInfo 获取值吗?你不应该使用这个:Where(p =&gt; p.GetValue(input).StartsWith... 吗?

标签: c# .net linq generics .net-core


【解决方案1】:

虽然问题的其余部分对我来说没有多大意义,但关于尝试制作通用函数的部分将需要为 Where 调用建立一个谓词

查看包含的 cmets 以获取有关如何构建用于谓词的 lambda 表达式的示例

public static class Filterclass {
    static readonly MethodInfo startsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string), typeof(System.StringComparison) });

    public static IEnumerable<T> FilterData<T>(this IEnumerable<T> input, string columnName, FilterModel filterModel) where T : class {
        var type = typeof(T);
        var propertyInfo = type.GetProperty(columnName);
        //T p =>
        var parameter = Expression.Parameter(type, "p");
        //T p => p.ColumnName
        var name = Expression.Property(parameter, propertyInfo);
        // filterModel.Term ?? String.Empty
        var term = Expression.Constant(filterModel.Term ?? String.Empty);
        //StringComparison.InvariantCultureIgnoreCase
        var comparison = Expression.Constant(StringComparison.InvariantCultureIgnoreCase);
        //T p => p.ColumnName.StartsWith(filterModel.Term ?? String.Empty, StringComparison.InvariantCultureIgnoreCase)
        var methodCall = Expression.Call(name, startsWith, term, comparison);

        var lambda = Expression.Lambda<Func<T, bool>>(methodCall, parameter);

        return input.Where(lambda.Compile())
        .Skip((filterModel.Page - 1) * filterModel.Limit)
        .Take(filterModel.Limit);
    }
}

现在假设列是字符串类型。任何其他类型都会导致它抛出异常。

您还需要假设 p 不是 null 否则在尝试调用空引用上的实例成员时将再次引发空引用异常。

正在使用的扩展方法的示例单元测试

[TestClass]
public class MyTestClass2 {
    [TestMethod]
    public void MyTestMethod() {
        //Arrange
        IEnumerable<Person> persons = new List<Person>() {
            new Person() { Name = "Nancy Davolio", DOB = DateTime.Parse("1948-12-08"), Email = "nancy.davolio@test.com" },
            new Person() { Name = "Andrew Fuller", DOB = DateTime.Parse("1952-02-19"), Email = "andrew.fuller@test.com" },
            new Person() { Name = "Janet Leverling", DOB = DateTime.Parse("1963-08-30"), Email = "janet.leverling@test.com" },
            new Person() { Name = "Margaret Peacock", DOB = DateTime.Parse("1937-09-19"), Email = "margaret.peacock@test.com" },
            new Person() { Name = "Steven Buchanan", DOB = DateTime.Parse("1955-03-04"), Email = "steven.buchanan@test.com" },
            new Person() { Name = "Michael Suyama", DOB = DateTime.Parse("1963-07-02"), Email = "michael.suyama@test.com" },
            new Person() { Name = "Robert King", DOB = DateTime.Parse("1960-05-29"), Email = "robert.king@test.com" },
            new Person() { Name = "Laura Callahan", DOB = DateTime.Parse("1958-01-09"), Email = "laura.callahan@test.com" },
            new Person() { Name = "Anne Dodsworth", DOB = DateTime.Parse("1966-01-27"), Email = "anne.dodsworth@test.com" }
        };

        var filter = new FilterModel {                
            Term = "Nancy"
        };

        //Act
        var data = persons.FilterData("Name", filter);

        //Assert
        data.Should().NotBeEmpty();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 1970-01-01
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 2018-12-29
    相关资源
    最近更新 更多