I have a lamda expression that is passed to a First() or FirstOrDefault() call. I would like to dynamically inject a parameter value into the lamda when it is executed.
this is the hacked code I have now; it "works" in the sense that it runs.
ObservableCollection<T> Rows { get; set; }
T currentRow = Rows[0];
Template r = (Template)(object)currentRow;
Func<T, bool> p = e => ((Template)(object)e).TemplateId.Equals(r.TemplateId);
var firstRow = Rows.First(p);
I would like something that handles the generic T properly
public class Model<T>
{
public ObservableCollection<T> Rows { get; set; } = {add rows here}
public Func<T, T, bool> Lamda { get; set; }
public T CompareRow {get; set;} // assume not null
public T SelectedRow { get; set; }
public GetRow()
{
T currentRow = CompareRow;
// First extension takes a lamda expression of Func<T,bool>
// SOMEHOW inject the runtime value of currentRow into Lamda
// to convert Func<T, T, bool> to Func<T, bool>
var firstRow = Rows.First(Lamda); // get first row that matches Lamda
SelectedRow = firstRow;
}
}
public class MyModel: Model<Entity>
{
public void MyModel() : base()
{
// define the lamda expression with the concrete type of <Entity>
// each <Entity> type has different fields;
// so want to define a Lamda in the concrete class to validate the fields,
// but one that can be used in the generic base class.
Func<Entity, Entity, bool> p = (e,r) => e.TemplateId.Equals(r.TemplateId);
Lamda = p;
}
public SetRow() // called from somewhere
{
CompareRow = Rows.Last(); // assume Rows is not empty
}
public GetRow()
{
base.GetRow();
}
}
I have found these...
[https://stackoverflow.com/questions/16985310/convert-expressionfunct-t-bool-to-expressionfunct-bool] (this has extra code in it... so can this be improved on?)
[https://stackoverflow.com/questions/21922214/create-dynamic-linq-expression-for-select-with-firstordefault-inside] (this is specific to creating a "select" lamda).
[https://www.codementor.io/@juliandambrosio/how-to-use-expression-trees-to-build-dynamic-queries-c-xyk1l2l82]
[https://stackoverflow.com/questions/63172233/dynamic-firstordefault-predicate-expression]
Also: if there is a different way to call var firstRow = Rows.First(Lamda); that is straight forward, open to suggestions.
CodePudding user response:
You can call your Lamda function this way.
public GetRow()
{
T currentRow = CompareRow;
var firstRow = Rows.First(row => Lamda(row, CompareRow)); // get first row that matches Lamda
SelectedRow = firstRow;
}
Here is another example using string parameters:
List<string> names = new() { "Alice", "Bob", "Charlie" };
string nameToMatch = "Alice";
Func<string, string, bool> Lambda = (left, right) => left.GetHashCode() == right.GetHashCode();
var alice = names.First(name => Lambda(name, nameToMatch));
Console.WriteLine($"Hi {alice}");
You may have some issues setting Lambda. The type looks wrong Func<Entity, Entity, bool> is not Func<T, T, bool> as there are no constraints on what type T is.
You may want to consider adding a constraint on T, maybe something like this:
public class Model<T>
where T : Entity
{
public Func<Entity, Entity, bool> Lamda { get; set; }
}
