使用反射在谓词中引用 class 的 属性
Reference to a property of class in predicate using reflection
我有一个简单的 class 有许多 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);
...
其中 Filter
方法是使用 LINQ Where
实现的,如第一个示例。
上面的代码当然不能编译,因为MyClass.Created
是胡说八道
肯定有一些使用反射的解决方案,但我对反射的经验很少。你能帮帮我吗?
您可以使用 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
替换为要使用的 属性 的选择器。
创建辅助方法
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;
}
}
}
我非常喜欢可读代码,其中方法名称解释了它们的作用。出于这个原因,我建议添加以下方法。它们可以像我的示例一样添加到数据 class 本身中,也可以添加到 "Filter" class.
中
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));
我有一个简单的 class 有许多 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);
...
其中 Filter
方法是使用 LINQ Where
实现的,如第一个示例。
上面的代码当然不能编译,因为MyClass.Created
是胡说八道
肯定有一些使用反射的解决方案,但我对反射的经验很少。你能帮帮我吗?
您可以使用 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
替换为要使用的 属性 的选择器。
创建辅助方法
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;
}
}
}
我非常喜欢可读代码,其中方法名称解释了它们的作用。出于这个原因,我建议添加以下方法。它们可以像我的示例一样添加到数据 class 本身中,也可以添加到 "Filter" class.
中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));