将属性getter传递给linq表达式函数

时间:2018-03-20 18:31:41

标签: c# generics

我正在尝试采用一种方法并使其成为通用的,我有点卡住,因为该方法使用Linq来查看元素。这是示例方法:

private List<int> GetListFromIDS(string ids, IEnumerable<SubSpace_Function> data)
{
    if (string.IsNullOrEmpty(ids))
        return null;

    var list = ids
        .Split(new char[] { ',' })
        .Where(x => !string.IsNullOrWhiteSpace(x))
        .Select(x => int.Parse(x.Trim()));

    return data
        .Where(x => list.Contains(x.Function_Id)))
        .Select(x => x.Function_Id)
        .ToList();
}

更改的部分是类型(SubSpace_Function)和要查找的属性Function_ID

我知道我可以在通用方法签名中将SubSpace_Function部分更改为T,但由于每种类型都有自己的属性来查找,我不知道如何'传递'像Function_Id

2 个答案:

答案 0 :(得分:1)

使用Func非常容易:

private List<int> GetListFromIDS<T>(string ids, IEnumerable<T> data, Func<T, IEnumerable<int>, bool> filterExpression, Func<T, int> selectExpression)
{
    if (string.IsNullOrEmpty(ids))
        return null;

    var list = ids
        .Split(',') // simplify
        .Where(x => !string.IsNullOrWhiteSpace(x))
        .Select(x => int.Parse(x.Trim()));

    return data
        .Where(x => filterExpression(x, list))
        .Select(selectExpression)
        .ToList();
}

并致电:

var data = GetListFromIDS<SubSpace_Function>(
    "123,123,123", 
    someList,
    (x, list) => list.Contains(x.Function_Id), 
    x => x.Function_Id);

另一种方法是调用select Func inline:

private List<int> GetListFromIDS<T>(string ids, IEnumerable<T> data, Func<T, int> selectExpression)
{
    if (string.IsNullOrEmpty(ids))
        return null;

    var list = ids
        .Split(',') // simplify
        .Where(x => !string.IsNullOrWhiteSpace(x))
        .Select(x => int.Parse(x.Trim()));

    return data
        .Where(x => list.Contains(selectExpression(x)))
        .Select(selectExpression)
        .ToList();
}

并致电:

var data = GetListFromIDS<SubSpace_Function>(
    "123,123,123", 
    someList,
    x => x.Function_Id);

答案 1 :(得分:0)

我知道这专注于泛型,但我采用了使用界面的方法:

interface ISubSpaceFunction
{
    int FunctionId { get; }
}

class Foo : ISubSpaceFunction
{
    public int FunctionId => FooMethodForFunctionId();

    private int FooMethodForFunctionId()
    {
        //do foo function id stuff
        throw new NotImplementedException();//so it compiles
    }
}

class Bar : ISubSpaceFunction
{
    public int FunctionId => BarMethodForFunctionId();

    private int BarMethodForFunctionId()
    {
        //do bar function id stuff
        throw new NotImplementedException();//so it compiles
    }
}

static class MyClass
{
    private static List<int> GetListFromIds(string idsString, IEnumerable<ISubSpaceFunction> subSpaceFunctions)
    {
        var ids = string.IsNullOrWhiteSpace(idsString) ?
            Enumerable.Empty<int>() :
            idsString.Split(new[] { ',' })
                     .Where(x => !string.IsNullOrWhiteSpace(x))
                     .Select(x => x.Trim())
                     .Select(int.Parse);

        var idSet = new HashSet<int>(ids);

        return subSpaceFunctions.Select(ssf => ssf.FunctionId)
                                .Where(ids.Contains)
                                .ToList();
    }
}

class Example
{
    public void Test()
    {
        string ids = "1, 2, 3, 4, 5";

        var subSpaceFunctions = new ISubSpaceFunction[] { new Foo(), new Bar() };

        var results = MyClass.GetListFromIds(ids, subSpaceFunctions);
    }
}

我对这个和相关问题的态度是,获取每个特定类型的Property值的代码必须某处,所以它也可以进入Type类。这确保了如果在其他地方需要Property的值,则不会重复。这也允许混合满足ISubSpaceFunction的多种类型,如示例中所做的那样,并且您可以轻松地让接口指定一些常用方法在其他地方使用。

在编写这些基于LINQ的转换方法时,我也更喜欢在null上返回空集合,以便最小化空值检查&#34;在管道中,&#34;但是快速失败&#34;用例可能会调用null返回值。