使用反射引用谓词中类的属性

时间:2015-10-27 13:56:03

标签: c# .net linq reflection properties

我有一个包含许多DateTime属性的简单类:

public class MyClass
{
    public DateTime Created {get; set;}
    public DateTime LastChanged {get; set;}
    public DateTime LastAccessed {get; set;}
    ...
}

稍后,在我的代码中的某个地方,我想根据这些属性过滤MyClass的集合。对于每个属性,我想做这样的事情:

myQueryableOfMyClass = myQueryableOfMyClass.Where(a => ((begin == null) || (a.Created >= begin)) && ((end == null) || (a.Created <= end));

如果我必须为我的每个DateTime属性执行此操作,那么很多代码会有一些拼写错误的风险,所以我想做类似的事情:

myQueryableOfMyClass = Filter(myQueryableOfMyClass, begin, end, MyClass.Created);
myQueryableOfMyClass = Filter(myQueryableOfMyClass, changebegin, changeend, MyClass.LastChanged);
myQueryableOfMyClass = Filter(myQueryableOfMyClass, accbegin, accend, MyClass.LastAccessed);
...

其中使用LINQ Filter实现Where方法,如第一个示例所示。

当然,上面的代码无法编译,因为MyClass.Created是无意义的。

必须有一些使用反射的解决方案,但我对反射的经验很少。你能帮我吗?

3 个答案:

答案 0 :(得分:4)

您可以使用Func<MyClass, DateTime>来选择要使用的属性,例如:

public static IEnumerable<MyClass> Filter
(
    IEnumerable<MyClass> myClasses, 
    DateTime? begin, 
    DateTime? end, 
    Func<MyClass, DateTime> selector
)
{
    return myClasses.Where(a => ((begin == null) || (selector(a) >= begin)) && ((end == null) || (selector(a)) <= end));
}

您可以这样称呼它:

Filter(myClasses, begin, end, myClass => myClass.Created);

您要将myClass => myClass.Created替换为您要使用的属性的选择器。

答案 1 :(得分:3)

我是可读代码的忠实粉丝,其中方法名称解释了他们的工作。出于这个原因,我建议添加以下方法。它们可以像我的例子一样在数据类中添加,也可以在“Filter”类中。

public class MyClass
{
    public DateTime Created { get; set; }
    public DateTime LastChanged { get; set; }
    public DateTime LastAccessed { get; set; }

    public bool WasCreatedInTimespan(DateTime? begin, DateTime? end)
    {
        return IsDateInTimespan(Created, begin, end);
    }

    public bool WasChangedInTimespan(DateTime? begin, DateTime? end)
    {
        return IsDateInTimespan(LastChanged, begin, end);
    }

    public bool WasAccessedInTimespan(DateTime? begin, DateTime? end)
    {
        return IsDateInTimespan(LastAccessed, begin, end);
    }

    private static bool IsDateInTimespan(DateTime date, DateTime? begin, DateTime? end)
    {
        return (!begin.HasValue || date >= begin.Value) && (!end.HasValue || date >= end.Value);
    }
}

使用这些方法,调用代码变得非常清晰。像这样:

var createdList = myQueryableOfMyClass.Where(m => m.WasCreatedInTimespan(begin, end));
var changedList = myQueryableOfMyClass.Where(m => m.WasChangedInTimespan(begin, end));
var accessedList = myQueryableOfMyClass.Where(m => m.WasAccessedInTimespan(begin, end));

答案 2 :(得分:1)

创建辅助方法

        public void test()
        {
           myQueryableOfMyClass = myQueryableOfMyClass.Where(a => Filter(begin, end, a));
        }



        public Boolean Filter(DateTime begin, DateTime end, DateTime date)
        {
            if(((begin == null) || (date >= begin)) && ((end == null) || (date <= end)))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }​