简体   繁体   English

如何创建谓词<t>在运行时动态</t>

[英]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.我检查了PredicateLambda 表达式以及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. isAlphaNumerichasName之间的主要区别在于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.

相关问题 如何动态创建谓词 - How to create predicate dynamically 在运行时动态生成谓词 - Dynamically generate predicate at runtime 我可以动态创建一个表达式 <Func<T, bool> &gt;谓词,但我如何创建表达式 <Func<T1,T2,bool> &gt; - I can dynamically create an Expression<Func<T, bool>> predicate ,but how do i create Expression<Func<T1,T2,bool>> 如何动态创建动作<T>在运行时? - How can I dynamically create an Action<T> at runtime? 如何获得谓词<T>从运行时的字符串表达式 - How to get Predicate<T> from string expressions at runtime 如何动态创建表达式<Func<MyClass, bool> &gt; 谓词? - How do I dynamically create an Expression<Func<MyClass, bool>> predicate? 在运行时动态创建变量 - Dynamically Create Variables At Runtime 通用过滤器类<T> - 在类列表中<predicate> (T) 应设置,如何在运行时使用未知类型? - Generic FilterClass<T> - within the class a List<predicate>(T) shall be set up, how with unknown type at runtime? 创建一个 lambda 表达式树,Expression <func<t, bool> >,动态地执行基于 Or、And 的谓词</func<t,> - create a lambda expression tree, Expression<Func<T, bool>>, dynamically that performs an Or-based, And-based predicate 如何指定谓词的类型,直到运行时才知道? - How can I specify a predicate's type, which I won't know until runtime?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM