[英]How to create a Predicate<T> dynamically on runtime
I am trying to create a method in a base class capable of taking parameters and creating a Predicate<T>
on the fly.我正在尝试在能够获取参数并动态创建
Predicate<T>
的基础 class 中创建一个方法。
Here is the abstract class:这是抽象的 class:
public abstract class Table<TResults>
where TResults : class
{
...
protected abstract List<TResults> Results { get; set; }
...
}
And here is one class implementing Table<TResults>
:这是一个实现
Table<TResults>
的 class :
public class TrStudent
{
...
public string Name => // some code
...
public void Check()
{
// check implementation
}
}
public class TableStudents : Table<TrStudent>
{
...
protected override List<TrStudent> Results { get; set; }
...
public void Check_Student(string studentName) => Results.Find(r => r.Name == studentName).Check();
}
And here is another class implementing Table<TResults>
:这是另一个实现
Table<TResults>
的 class :
public class TrAnswer
{
...
public string Name => // some code
public int Id => // some other code
...
public void Report()
{
// report implementation
}
}
public class TableAnswers<TrAnswer> : Table<TrAnswer>
{
...
protected override List<TrAnswer> Results { get; set; }
...
public void Report_Answer(string answerName, int answerId) => Results.Find(r => r.Name == answerName && r.Id == answerId).Report();
...
}
What I would like to do, if possible is update the Table<TResults>
class to:如果可能的话,我想做的是将
Table<TResults>
class 更新为:
public abstract class Table<TResults>
where TResults : class
{
...
protected abstract List<TResults> Results { get; set; }
...
protected abstract Predicate<T> Predicate { get; }
protected T Find(parameters) => Results.Find(parameters, Predicate);
}
So I can update the derived classes to:所以我可以将派生类更新为:
public class TableStudents : Table<TrStudent>
{
...
public void Check_Student(string studentName) => Find(studentName).Check();
}
public class TableAnswers<TrAnswer> : Table<TrAnswer>
{
...
public void Report_Answer(string answerName, int answerId) => Find(answerName, answerId).Report();
}
But I am not sure if this is possible as some lambdas take more parameters than others.但我不确定这是否可能,因为某些 lambda 比其他 lambda 采用更多参数。
I have checked Predicate , Lambda expressions and also Expression class and I am almost sure it could be done, but I dont know where to start.我检查了Predicate 、 Lambda 表达式以及Expression class ,我几乎可以肯定它可以完成,但我不知道从哪里开始。
Thanks for your time.谢谢你的时间。
Is the following not an option?以下不是一个选项吗?
public abstract class Table<TResults> where TResults : class {
// ...
protected TResults Find(Predicate<TResults> predicate)
=> Results.Find(predicate);
}
public class TableStudents : Table<TrStudent> {
// ...
public void Check_Student(string studentName)
=> Find(r => r.Name == studentName).Check();
}
public class TableAnswers<TrAnswer> : Table<TrAnswer>
{
// ...
public void Report_Answer(string answerName, int answerId)
=> Find(r => r.Name == answerName && r.Id == answerId).Report();
}
I don't see the point in going through the hazzle to create a Predicate<T>
at runtime.我没有看到在运行时创建
Predicate<T>
的麻烦。
Generally your solution looks a little bit too over-engineered, to be honest.一般来说,老实说,您的解决方案看起来有点过度设计。 What's the point of abstracting
List.Find()
when each subclass has to override the List
of results anyway?当每个子类都必须覆盖结果
List
时,抽象List.Find()
有什么意义?
Those subclasses literally have everything they need to filter their results (ie, the results itself and the predicate parameters), but still they must ask the abstract base class to filter for them?这些子类实际上拥有过滤其结果所需的一切(即结果本身和谓词参数),但它们仍然必须要求抽象基础 class 过滤它们吗?
If you need the predicate multiple times you could use a private function in each subclass that returns the Predicate<TResults>
for the given parameters:如果您多次需要谓词,您可以在每个返回给定参数的
Predicate<TResults>
的子类中使用私有 function :
public class TableStudents : Table<TrStudent> {
// ...
public void Check_Student(string studentName)
=> Find(FilterBy(studentName)).Check();
private static Predicate<TrStudent> FilterBy(string studentName)
=> r => r.Name == studentName;
}
public class TableAnswers<TrAnswer> : Table<TrAnswer>
{
// ...
public void Report_Answer(string answerName, int answerId)
=> Find(FilterBy(answerName, answerId)).Report();
private static Predicate<TrAnswer> FilterBy(string answerName, int answerId)
=> r => r.Name == answerName && r.Id == answerId;
}
Don't feel compelled to extract those private FilterBy()
functions into the base class only because they got identical names and work similarly.不要仅仅因为它们具有相同的名称并且工作相似,就不得不将那些私有
FilterBy()
函数提取到基本 class 中。 How a subclass filters is none of the base classes business.子类如何过滤与基类无关。 The subclass knows best how to filter its results and it might or might not use one or more private functions to create the
Predicate<T>
s it needs.子类最清楚如何过滤其结果,它可能会或可能不会使用一个或多个私有函数来创建它需要的
Predicate<T>
。
Note that FilterBy()
is a function that returns a Predicate<T>
.请注意,
FilterBy()
是返回Predicate<T>
的 function 。 A Predicate<T>
is a function object that returns a bool
when you give it a T
value. Predicate<T>
是一个 function object 当你给它一个T
值时返回一个bool
值。
It's similar to a regular function like bool MyPredicate(T value) {...}
, only that you can store it in variables, pass it around, and even return it from other functions:它类似于
bool MyPredicate(T value) {...}
之类的常规 function ,只是您可以将其存储在变量中,传递它,甚至从其他函数中返回它:
// create function object
var isAlphaNumeric = new Predicate<char>(c => char.IsLetter(c) || char.IsDigit(c));
// call function object with some values
Debug.Assert(isAlphaNumeric('a') == true);
Debug.Assert(isAlphaNumeric('&') == false);
This more verbose version of FilterBy()
might make the relation to isAlphaNumeric
more clear:这个更详细的
FilterBy()
版本可能会使与isAlphaNumeric
的关系更加清晰:
private static Predicate<TrStudent> FilterBy(string studentName) {
var hasName = new Predicate<TrStudent>(r => r.Name == studentName);
return hasName;
}
The major difference between isAlphaNumeric
and hasName
is that hasName
needs to capture the value of the studentName
parameter by storing it inside the function object. isAlphaNumeric
和hasName
之间的主要区别在于hasName
需要通过将studentName
参数的值存储在 function object 中来捕获它的值。 Later, when the returned hasName
function object is called by List.Filter()
with one or more TrStudent
objects, this value will be available for the name comparison.稍后,当返回的
hasName
function object 通过一个或多个TrStudent
对象被List.Filter()
调用时,该值将可用于名称比较。
By the way, a function returning a function (or taking other functions as parameters) are so called higher-order functions .顺便说一句,返回 function(或以其他函数为参数)的 function 就是所谓的高阶函数。 C# took them from functional programming and they are very powerful.
C# 从函数式编程中获取它们,它们非常强大。 For instance, LINQ wouldn't be possible without them.
例如,没有它们,LINQ 是不可能的。 But they can also replace some object-oriented design patterns like the strategy pattern, the template method pattern, the factory patterns, and even dependency injection.
但它们也可以替代一些面向对象的设计模式,如策略模式、模板方法模式、工厂模式,甚至依赖注入。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.