score:0
Here's a working program that does what I think you'd like. It defines a function that takes a path to an integer property inside a collection, and an integer value. It then checks whether or not that collection has Count > 0 of that value.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections;
namespace Test_Console
{
public class Subscription
{
public int Id { get; set; }
public Client Client { get; set; }
}
public class Client
{
public ICollection<Invoice> Invoices { get; set; }
}
public class Invoice
{
public int Id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var subscriptions = new[]
{
new Subscription { Id = 1, Client = new Client { Invoices = new [] {
new Invoice { Id = 1 },
new Invoice { Id = 2 },
new Invoice { Id = 5 }
} } },
new Subscription { Id = 2, Client = new Client { Invoices = new [] {
new Invoice { Id = 4 },
new Invoice { Id = 5 },
new Invoice { Id = 5 }
} } },
new Subscription { Id = 3, Client = new Client { Invoices = new Invoice[] {
} } },
};
var propertyPath = "Client.Invoices.Id";
Console.WriteLine("What Id would you like to check " + propertyPath + " for?");
var propertyValue = int.Parse(Console.ReadLine());
var whereNumberOne = makeWhere<Subscription>(propertyPath, propertyValue);
Console.WriteLine("The following Subscription objects match:");
foreach (var s in subscriptions.Where(whereNumberOne).ToList())
{
Console.WriteLine("Id: " + s.Id);
}
}
private static Func<T, bool> makeWhere<T>(string propertyPath, int propertyValue)
{
string[] navigateProperties = propertyPath.Split('.');
var currentType = typeof(T);
var functoidChain = new List<Func<object, object>>();
functoidChain.Add(x => x); // identity function starts the chain
foreach (var nextProperty in navigateProperties)
{
// must be inside loop so the closer on the functoids works properly
PropertyInfo nextPropertyInfo;
if (currentType.IsGenericType
&& currentType.GetGenericTypeDefinition().GetInterfaces().Contains(typeof(IEnumerable)))
{
nextPropertyInfo = currentType.GetGenericArguments()[0].GetProperty(nextProperty);
functoidChain.Add(x =>
((IEnumerable<object>)x)
.Count(y => (int)nextPropertyInfo.GetValue(y, null) == propertyValue)
);
}
else
{
nextPropertyInfo = currentType.GetProperty(nextProperty);
functoidChain.Add(x => nextPropertyInfo.GetValue(x, null));
}
currentType = nextPropertyInfo.PropertyType;
}
// compose the functions together
var composedFunctoidChain = functoidChain.Aggregate((f, g) => x => g(f(x)));
var leftSide = new Func<T, int>(x => (int)composedFunctoidChain(x));
return new Func<T, bool>(r => leftSide(r) > 0);
}
}
}
score:0
I think this should get you closer to what you're going for:
static Expression<Func<T, bool>> CreateAnyExpression<T, T2>(string propertyPath,
Expression<Func<T2, bool>> matchExpression)
{
var type = typeof(T);
var parameterExpression = Expression.Parameter(type, "s");
var propertyNames = propertyPath.Split('.');
Expression propBase = parameterExpression;
foreach(var propertyName in propertyNames)
{
PropertyInfo property = type.GetProperty(propertyName);
propBase = Expression.Property(propBase, property);
type = propBase.Type;
}
var itemType = type.GetGenericArguments()[0];
// .Any(...) is better than .Count(...) > 0
var anyMethod = typeof(Enumerable).GetMethods()
.Single(m => m.Name == "Any" && m.GetParameters().Length == 2)
.MakeGenericMethod(itemType);
var callToAny = Expression.Call(anyMethod, propBase, matchExpression);
return Expression.Lambda<Func<T, bool>>(callToAny, parameterExpression);
}
Calling it like this:
CreateAnyExpression<Subscription, Invoice>("Client.Invoices", i => i.InvoiceID == 1)
... yields the following Expression<Func<Subscription,bool>>
:
s => s.Client.Invoices.Any(i => (i.InvoiceID == 1))
score:0
Here's a working program building Linq Expression
{(x.Children.Count(y => y.SomeID == SomeVar) > 0)}
using System;
using System.Linq;
using System.Linq.Expressions;
namespace ExpressionTree
{
class Program
{
static void Main(string[] args)
{
ParameterExpression foundX = Expression.Parameter(typeof(Parent), "x");
Guid[] guids = new Guid[1] { Guid.NewGuid() };
Expression expression = GetCountWithPredicateExpression(guids, foundX);
}
private static Expression GetCountWithPredicateExpression(Guid[] idsToFilter, ParameterExpression foundX)
{
System.Reflection.PropertyInfo childIDPropertyInfo = typeof(Child).GetProperty(nameof(Child.SomeID));
ParameterExpression foundY = Expression.Parameter(typeof(Child), "y");
Expression childIDLeft = Expression.Property(foundY, childIDPropertyInfo);
Expression conditionExpression = Expression.Constant(false, typeof(bool));
foreach (Guid id in idsToFilter)
conditionExpression = Expression.Or(conditionExpression, Expression.Equal(childIDLeft, Expression.Constant(id)));
Expression<Func<Child, bool>> idLambda = Expression.Lambda<Func<Child, bool>>(conditionExpression, foundY);
var countMethod = typeof(Enumerable).GetMethods()
.First(method => method.Name == "Count" && method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(Child));
System.Reflection.PropertyInfo childrenPropertyInfo = typeof(Parent).GetProperty("Children");
Expression childrenLeft = Expression.Property(foundX, childrenPropertyInfo);
Expression ret = Expression.GreaterThan(Expression.Call(countMethod, childrenLeft, idLambda), Expression.Constant(0));
return ret;
}
}
public class Parent
{
public Child[] Children { get; set; }
}
public class Child
{
public int ID { get; set; }
public Guid SomeID { get; set; }
}
}
Source: stackoverflow.com
Related Articles
- How to count the number of code lines in a C# solution, without comments and empty lines, and other redundant stuff, etc?
- Group by, Count and Lambda Expression
- passing dynamic expression to order by in code first EF repository
- How to reuse a linq expression for 'Where' when using multiple source tables
- Get Value and Count of that value using LINQ or lambda expression
- Count in lambda expression
- LINQ with Lambda expression - Join, Group By, Sum and Count
- How do I build Expression Call for Any Method with generic parameter
- Dynamic Lambda Expression call
- Execute expression on another IQueryable source
- LINQ Source Code Available
- How to call a lambda using LINQ expression trees in C# / .NET
- Call Ignore Case for Contains Method using a generic LINQ Expression
- Best way to call an instance method in Expression Trees?
- Find Count using lambda Expression
- prevent unnecessary cross joins in count query of generated sql code
- .NET 4 Code Contracts: "requires unproven: source != null"
- Count and distinct count in one LINQ expression
- Convert SQL to linq expression with count
- Expression Trees: Filtered count on navigation property
- An expression tree may not contain a call or invocation that uses option arguments in C# Linq
- Call Enumerable Average via expression
- Nested Expression method call in Linq.Select()
- linq count error: DbExpressionBinding requires an input expression with a collection ResultType. Parameter name: input
- How to a compose a Linq Expression to call OrderBy on a set of entities?
- Help with Linq expression to return a list of strings based on field count
- creating Linq to sqlite dbml from DbLinq source code
- Getting multiple count in EF Model LINQ in single DB call
- Linq to Sql: Optimizing lamba expression - clean code
- Lambda Expression for Many to Many realtionship in C# EF 5 Code First
- Algorithm: two tables are in connection with ID, calculating a new table from them
- Anonymous type and intersection of 2 lists
- Linq Combine Fields
- How can I filter records in an SQLite database against a DateTime value that was not supplied?
- Count and group by month with Linq
- Using linq to get nth word from each line in a list in C#
- What is the difference between LINQ query expressions and extension methods
- Errors using a LINQ query in a Silverlight application
- Getting all elements concatenate in a string with LINQ
- HTML Agility Pack and LINQ
- How to Query and Enumerate complex JSON object using JSON.Net in C#
- MVC C# Select Where
- LINQ group by query using reflected property name
- How to make a right join using LINQ to SQL & C#?
- Linq to Sharepoint results in invalid cast
- Split collection into groups of different sizes
- error when converting linq lambda query to list
- How to remove duplicates (distinct values) with out primary key
- EntityFramework Casting issues
- Linq select statement but require no from line