I want combine my expression built in runtime (CustomExpression) with ordinary select clausule. Is there any way in C# to do this without manually building whole expression?
var dto = iqueryable.Select(d => new DTO()
{
X = d.X,
Y = d.Y,
Z = CustomExpression
}
Where CustomExpression is something like this:
private Expression<Func<EntityTypeFromIQueryable, string>> CustomExpression() {
get {
// there is manually built expression like this:
return x => x.Blah
}
}
You have to insert some kind of compilable placeholder (like an Extension Method) into your expression first. Then, at runtime, you can modify the expression using an Expression Visitor to replace your "placeholder" with the actual lambda expression. Since your actual expression uses different Parameters (d vs. x) you have to replace them with those of the "original" expression.
In fact, i'm playing around with such scenarios within this project, where i've tried to abstract this kind of expression plumbing. Your "combine" would then look like that:
var dto = iqueryable.ToInjectable().Select(d => new DTO()
{
X = d.X,
Y = d.Y,
Z = d.CustomExpression()
}
public static class CustomExpressions
{
[InjectLambda]
public static string CustomExpression(this EntityTypeFromIQueryable value)
{
// this function is just a placeholder
// you can implement it for non LINQ use too...
throw new NotImplementedException();
}
public static Expression<Func<EntityTypeFromIQueryable, string>> CustomExpression()
{
return x => x.Blah
}
}
The call ToInjectable() creates a lightweight proxy around the original Queryable to modify the expression before execution as described. The attribute InjectLambda marks the "placeholder" as "inject lambda here". By convention the actual expression returned by ToInjectable() gets inserted at the desired position.
You can do it in following way:
static void MultipleExpressionInSelectStatement()
{
List<person> p = new List<person>();
p.Add(new person() { name = "AB", age = 18 });
p.Add(new person() { name = "CD", age = 45 });
var dto = p.Select(d => new person()
{
name=d.name,
age=p.Select(ListExtensions.CustomExpression()).ElementAt(0)
});
}
//customExpression
public static class ListExtensions
{
public static Func<person, int> CustomExpression()
{
return x => x.age;
}
}
//Person Object
public class person
{
public string name { get; set; }
public int age { get; set; }
}
Related
This question already has answers here:
Dynamic LINQ OrderBy on IEnumerable<T> / IQueryable<T>
(24 answers)
Closed 2 years ago.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
I'm attempting to use a variable inside of a LINQ select statement.
Here is an example of what I'm doing now.
using System;
using System.Collections.Generic;
using System.Linq;
using Faker;
namespace ConsoleTesting
{
internal class Program
{
private static void Main(string[] args)
{
List<Person> listOfPersons = new List<Person>
{
new Person(),
new Person(),
new Person(),
new Person(),
new Person(),
new Person(),
new Person(),
new Person(),
new Person(),
new Person(),
new Person()
};
var firstNames = Person.GetListOfAFirstNames(listOfPersons);
foreach (var item in listOfPersons)
{
Console.WriteLine(item);
}
Console.WriteLine();
Console.ReadKey();
}
public class Person
{
public string City { get; set; }
public string CountryName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Person()
{
FirstName = NameFaker.Name();
LastName = NameFaker.LastName();
City = LocationFaker.City();
CountryName = LocationFaker.Country();
}
public static List<string> GetListOfAFirstNames(IEnumerable<Person> listOfPersons)
{
return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList();
}
public static List<string> GetListOfCities(IEnumerable<Person> listOfPersons)
{
return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList();
}
public static List<string> GetListOfCountries(IEnumerable<Person> listOfPersons)
{
return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList();
}
public static List<string> GetListOfLastNames(IEnumerable<Person> listOfPersons)
{
return listOfPersons.Select(x => x.FirstName).Distinct().OrderBy(x => x).ToList();
}
}
}
}
I have a Some very not DRY code with the GetListOf... Methods
i feel like i should be able to do something like this
public static List<string> GetListOfProperty(
IEnumerable<Person> listOfPersons, string property)
{
return listOfPersons.Select(x =>x.property).Distinct().OrderBy(x=> x).ToList();
}
but that is not vaild code. I think the key Might Relate to Creating a Func
if That is the answer how do I do that?
Here is a second attempt using refelection But this is also a no go.
public static List<string> GetListOfProperty(IEnumerable<Person>
listOfPersons, string property)
{
Person person = new Person();
Type t = person.GetType();
PropertyInfo prop = t.GetProperty(property);
return listOfPersons.Select(prop).Distinct().OrderBy(x =>
x).ToList();
}
I think the refection might be a DeadEnd/red herring but i thought i would show my work anyway.
Note Sample Code is simplified in reality this is used to populate a datalist via AJAX to Create an autocomplete experience. That object has 20+ properties and I can complete by writing 20+ methods but I feel there should be a DRY way to complete this. Also making this one method also would clean up my controller action a bunch also.
Question:
Given the first section of code is there a way to abstract those similar methods into a single method buy passing some object into the select Statement???
Thank you for your time.
You would have to build the select
.Select(x =>x.property).
by hand. Fortunately, it isn't a tricky one since you expect it to always be the same type (string), so:
var x = Expression.Parameter(typeof(Person), "x");
var body = Expression.PropertyOrField(x, property);
var lambda = Expression.Lambda<Func<Person,string>>(body, x);
Then the Select above becomes:
.Select(lambda).
(for LINQ based on IQueryable<T>) or
.Select(lambda.Compile()).
(for LINQ based on IEnumerable<T>).
Note that anything you can do to cache the final form by property would be good.
From your examples, I think what you want is this:
public static List<string> GetListOfProperty(IEnumerable<Person>
listOfPersons, string property)
{
Type t = typeof(Person);
PropertyInfo prop = t.GetProperty(property);
return listOfPersons
.Select(person => (string)prop.GetValue(person))
.Distinct()
.OrderBy(x => x)
.ToList();
}
typeof is a built-in operator in C# that you can "pass" the name of a type to and it will return the corresponding instance of Type. It works at compile-time, not runtime, so it doesn't work like normal functions.
PropertyInfo has a GetValue method that takes an object parameter. The object is which instance of the type to get the property value from. If you are trying to target a static property, use null for that parameter.
GetValue returns an object, which you must cast to the actual type.
person => (string)prop.GetValue(person) is a lamba expression that has a signature like this:
string Foo(Person person) { ... }
If you want this to work with any type of property, make it generic instead of hardcoding string.
public static List<T> GetListOfProperty<T>(IEnumerable<Person>
listOfPersons, string property)
{
Type t = typeof(Person);
PropertyInfo prop = t.GetProperty(property);
return listOfPersons
.Select(person => (T)prop.GetValue(person))
.Distinct()
.OrderBy(x => x)
.ToList();
}
I would stay away from reflection and hard coded strings where possible...
How about defining an extension method that accepts a function selector of T, so that you can handle other types beside string properties
public static List<T> Query<T>(this IEnumerable<Person> instance, Func<Person, T> selector)
{
return instance
.Select(selector)
.Distinct()
.OrderBy(x => x)
.ToList();
}
and imagine that you have a person class that has an id property of type int besides those you already expose
public class Person
{
public int Id { get; set; }
public string City { get; set; }
public string CountryName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
all you need to do is fetch the results with type safe lambda selectors
var ids = listOfPersons.Query(p => p.Id);
var firstNames = listOfPersons.Query(p => p.FirstName);
var lastNames = listOfPersons.Query(p => p.LastName);
var cityNames = listOfPersons.Query(p => p.City);
var countryNames = listOfPersons.Query(p => p.CountryName);
Edit
As it seems you really need hardcoded strings as the property inputs, how about leaving out some dynamism and use a bit of determinism
public static List<string> Query(this IEnumerable<Person> instance, string property)
{
switch (property)
{
case "ids": return instance.Query(p => p.Id.ToString());
case "firstName": return instance.Query(p => p.FirstName);
case "lastName": return instance.Query(p => p.LastName);
case "countryName": return instance.Query(p => p.CountryName);
case "cityName": return instance.Query(p => p.City);
default: throw new Exception($"{property} is not supported");
}
}
and access the desired results as such
var cityNames = listOfPersons.Query("cityName");
You should be able to do it with Reflection. I use it something similar.
Just change your reflection try to this:
public static List<string> GetListOfValues(IEnumerable<Person> listOfPersons, string propertyName)
{
var ret = new List<string>();
PropertyInfo prop = typeof(Person).GetProperty(propertyName);
if (prop != null)
ret = listOfPersons.Select(p => prop.GetValue(p).ToString()).Distinct().OrderBy(x => x).ToList();
return ret;
}
I hope it helps.
It's based on C# 6
You can also use this. works for me.
public static class ObjectReflectionExtensions
{
public static object GetValueByName<T>(this T thisObject, string propertyName)
{
PropertyInfo prop = typeof(T).GetProperty(propertyName);
return prop.GetValue(thisObject);
}
}
And call like this.
public static List<string> GetListOfProperty(IEnumerable<Person> listOfPersons, string propertyName)
{
return listOfPersons.Select(x =>(string)x.GetValueByName(propertyName)).Distinct().OrderBy(x=> x).ToList();
}
If you want to select all the values:
object[] foos = objects.Select(o => o.GetType().GetProperty("PropertyName").GetValue(o)).ToArray();
I am developing a small framework to access the database. I want to add a feature that makes a query using a lambda expression. How do I do this?
public class TestModel
{
public int Id {get;set;}
public string Name {get;set;}
}
public class Repository<T>
{
// do something.
}
For example:
var repo = new Repository<TestModel>();
var query = repo.AsQueryable().Where(x => x.Name == "test");
// This query must be like this:
// SELECT * FROM testmodel WHERE name = 'test'
var list = query.ToDataSet();
// When I call ToDataSet(), it will get the dataset after running the made query.
Go on and create a LINQ Provider (I am sure you don't want to do this, anyway).
It's a lot of work, so maybe you just want to use NHibernate or Entity Framework or something like that.
If your queries are rather simple, maybe you don't need a full blown LINQ Provider. Have a look at Expression Trees (which are used by LINQ Providers).
You can hack something like this:
public static class QueryExtensions
{
public static IEnumerable<TSource> Where<TSource>(this Repo<TSource> source, Expression<Func<TSource, bool>> predicate)
{
// hacks all the way
dynamic operation = predicate.Body;
dynamic left = operation.Left;
dynamic right = operation.Right;
var ops = new Dictionary<ExpressionType, String>();
ops.Add(ExpressionType.Equal, "=");
ops.Add(ExpressionType.GreaterThan, ">");
// add all required operations here
// Instead of SELECT *, select all required fields, since you know the type
var q = String.Format("SELECT * FROM {0} WHERE {1} {2} {3}", typeof(TSource), left.Member.Name, ops[operation.NodeType], right.Value);
return source.RunQuery(q);
}
}
public class Repo<T>
{
internal IEnumerable<T> RunQuery(string query)
{
return new List<T>(); // run query here...
}
}
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var repo = new Repo<TestModel>();
var result = repo.Where(e => e.Name == "test");
var result2 = repo.Where(e => e.Id > 200);
}
}
Please, don't use this as it is. This is just a quick and dirty example how expression trees can be analyzed to create SQL statements.
Why not just use Linq2Sql, NHibernate or EntityFramework...
if you want to do things like
db.Employee
.Where(e => e.Title == "Spectre")
.Set(e => e.Title, "Commander")
.Update();
or
db
.Into(db.Employee)
.Value(e => e.FirstName, "John")
.Value(e => e.LastName, "Shepard")
.Value(e => e.Title, "Spectre")
.Value(e => e.HireDate, () => Sql.CurrentTimestamp)
.Insert();
or
db.Employee
.Where(e => e.Title == "Spectre")
.Delete();
Then check out this, BLToolkit
You might want to look at http://iqtoolkit.codeplex.com/ Which is very complex and i dont recommend you to build something from scratch.
I just wrote something close to dkons's answer I will add it anyway. Just using fluent interface nothing more.
public class Query<T> where T : class
{
private Dictionary<string, string> _dictionary;
public Query()
{
_dictionary = new Dictionary<string, string>();
}
public Query<T> Eq(Expression<Func<T, string>> property)
{
AddOperator("Eq", property.Name);
return this;
}
public Query<T> StartsWith(Expression<Func<T, string>> property)
{
AddOperator("Sw", property.Name);
return this;
}
public Query<T> Like(Expression<Func<T, string>> property)
{
AddOperator("Like", property.Name);
return this;
}
private void AddOperator(string opName, string prop)
{
_dictionary.Add(opName,prop);
}
public void Run(T t )
{
//Extract props of T by reflection and Build query
}
}
Lets say you have a model like
class Model
{
public string Surname{ get; set; }
public string Name{ get; set; }
}
You can use this as :
static void Main(string[] args)
{
Model m = new Model() {Name = "n", Surname = "s"};
var q = new Query<Model>();
q.Eq(x => x.Name).Like(x=>x.Surname).Run(m);
}
Basically, I want to be able to create an Object and pass in a LINQ query to it as a property and store that property...
I know I could always just run the LINQ query in the code that wants to filter a collection, but I thought it'd be interesting if my Object could retain that query so that other classes that reference it can grab that query...
Pseudo-Code
public class MyClass
{
public MyClass(?? linq)
{
TheLinq = linq;
}
public ?? TheLinq { get; set; }
}
It sounds like you want something very close to the following:
public class Program {
private static void Main(string[] args) {
Func<List<string>, IEnumerable> testQuery = x => x.Where<IEnumerable>(y => !y.Equals("Yucky"));
var testArray=new string[] {"Hello", "Yucky", " ", "World"};
var testClass=new MyClass(testQuery);
var resultStrings = testClass.query(testArray.ToList());
// Printing resultStrings should result in "Hello World"
foreach (string s in resultStrings) {
Console.Write(s);
}
}
}
public class MyClass {
public Func<List<string>, IEnumerable> query { get; private set; }
public MyClass(Func<List<string>, IEnumerable> aQuery)
{
query=aQuery;
}
}
EDIT: Checked, and yes this does work
In general, you will need to tailor the Func<input, output> as you would like it to end up, but this should work perfectly well for you, I should think!
And just for a little bit of read-ability, the func here could be rewritten with less ambiguous variable names like: Func<List<string>, IEnumerable> testQuery = theListToQuery => theListToQuery.Where<IEnumerable>(stringInList => !stringInList.Equals("Yucky"));
If you are looking to retain the query expression and manipulate it, consider the following:
public class MyClass
{
public MyClass(IQueryable<MyClass> linq)
{
TheLinq = linq;
}
public IQueryable<MyClass> TheLinq { get; set; }
}
I think you are looking to use Expression Trees. The Expression objects (expr and expr1) are instances of the type you are trying to explain above. These expression objects can be passed around and compiled as necessary:
List<int> ints = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9};
Expression<Func<IEnumerable<int>, IEnumerable<int>>> expr = x=> x.Where(y=> y>6);
Expression<Func<IEnumerable<int>, IEnumerable<IGrouping<bool,int>>>> expr1 = x => x.GroupBy(y => y > 6);
// first expression
var bobs = expr.Compile()(ints);
foreach(var bob in bobs)
{
Console.WriteLine(bob);
}
// second expression
var bobs1 = expr1.Compile()(ints);
int counter = 0;
foreach (IGrouping<bool, int> bob in bobs1)
{
Console.WriteLine("group " + counter++ + " values :");
foreach (var t in bob)
{
Console.WriteLine(t);
}
}
I need to support a variable number of Orderby terms in a Linq (to Entity) statement. That is, my function will accept a list of properties on which the data should be order. The properties can have both ascending or descending sorts. What is the best way to handle constructing the Linq query?
Thanks!
You should be able to do something along these lines:
public IEnumerable<MyType> DoSomething(params Expression<Func<MyType,object>>[] properties)
{
var query = // create LINQ query that returns IQueryable<MyType>
query = query.OrderBy(properties.First());
foreach (var property in properties.Skip(1))
{
query = query.ThenBy(property);
}
}
…
var results = DoSomething(() => x.Age, () => x.Height, () => x.LastName);
You'd need to handle the case where fewer than 2 properties are specified.
Following on from Jay's answer, this can be made into a nice extension method:
public static class EnumerableExtensions
{
public static IEnumerable<T> OrderByMany<T>(this IEnumerable<T> enumerable,
params Expression<Func<T, object>>[] expressions)
{
if (expressions.Length == 1)
return enumerable.OrderBy(expressions[0].Compile());
var query = enumerable.OrderBy(expressions[0].Compile());
for (int i = 1; i < expressions.Length;i++)
{
query = query.ThenBy(expressions[i].Compile());
}
return query;
}
}
Usage becomes quite simple, given a test object:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
This is then possible:
var people = new Person[]
{
new Person() {Name = "John", Age = 40},
new Person() {Name = "John", Age = 20},
new Person() {Name = "Agnes", Age = 11}
};
foreach(var per in people.OrderByMany(x => x.Name, x => x.Age))
{
Console.WriteLine("{0} Age={1}",per.Name,per.Age);
}
Output:
Agnes Age=11
John Age=20
John Age=40
UPDATE
You could add another overload of the OrderByMany method to support SortOrder as well, although it gets clunky rather quickly. Personally I'd just go for the syntax
var query = from p
in people
order by Name, Age descending;
However, for the record, in C#4 at least, I would accomplish the overload using an enum & tuple.
public enum SortOrder
{
Ascending,
Descending
}
and the extra overload:
public static IEnumerable<T> OrderByMany<T>(this IEnumerable<T> enumerable,
params Tuple<Expression<Func<T, object>>,SortOrder>[] expressions)
{
var query = (expressions[0].Item2 == SortOrder.Ascending)
? enumerable.OrderBy(expressions[0].Item1.Compile())
: enumerable.OrderByDescending(expressions[0].Item1.Compile());
for (int i = 1; i < expressions.Length; i++)
{
query = expressions[i].Item2 == SortOrder.Ascending
? query.ThenBy(expressions[i].Item1.Compile())
: query.ThenByDescending(expressions[i].Item1.Compile());
}
return query;
}
Usage becomes clumsy and hard to read:
foreach (var per in people.OrderByMany(
new Tuple<Expression<Func<Person, object>>, SortOrder>(x => x.Age, SortOrder.Descending),
new Tuple<Expression<Func<Person, object>>, SortOrder>(x => x.Name, SortOrder.Ascending)))
{
Console.WriteLine("{0} Age={1}", per.Name, per.Age);
}
To sort by an arbitrary property, you need to build an expression tree to pass to OrderBy.
To sort by an arbitrary number of properties, you need to call ThenBy in a loop.
I like Jamiec's idea but I hate using Tuples because the syntax is ugly. Therefore I built a small class that encapsulates the Tuple and exposes getters for the Item1 and Item2 properties with better variable names.
Also notice that I used a default sort order of ascending so you only need to specify a SortOrder if you want to sort in descending order.
public class SortExpression<T>
{
private Tuple<Expression<Func<T, object>>, SortOrder> tuple;
public SortExpression( Expression<Func<T, object>> expression, SortOrder order =SortOrder.Ascending )
{
tuple = new Tuple<Expression<Func<T,object>>, SortOrder>(expression, order);
}
public Expression<Func<T, object>> Expression {
get { return tuple.Item1; }
}
public SortOrder Order {
get { return tuple.Item2; }
}
}
In my specific application, I have a repository base class which takes an IQueryable and converts it to a ObservableCollection. In that method I use the SortExpression class:
public ObservableCollection<T> GetCollection(params SortExpression<T>[] sortExpressions) {
var list = new ObservableCollection<T>();
var query = FindAll();
if (!sortExpressions.Any()) {
query.ToList().ForEach(list.Add);
return list;
}
var ordered = (sortExpressions[0].Order == SortOrder.Ascending)
? query.OrderBy(sortExpressions[0].Expression.Compile())
: query.OrderByDescending(sortExpressions[0].Expression.Compile());
for (var i = 1; i < sortExpressions.Length; i++) {
ordered = sortExpressions[i].Order == SortOrder.Ascending
? ordered.ThenBy(sortExpressions[i].Expression.Compile())
: ordered.ThenByDescending(sortExpressions[i].Expression.Compile());
}
ordered.ToList().ForEach(list.Add);
return list;
}
Here is the method in use:
var repository = new ContactRepository(UnitOfWork);
return repository.GetCollection(
new SortExpression<Contact>(x => x.FirstName),
new SortExpression<Contact>(x => x.LastName));
I need to calculate a whole bunch of averages on an List of Surveys. The surveys have lots of properties that are int and double valued. I am creating a business object to handle all the calculations (there are like 100) and I'd rather not code 100 different methods for finding the average for a particular property.
I'd like to be able to have the UI pass a string (representing the property) and have the the business object return an average for that property.
So, like...
int AverageHeightInInches = MyObject.GetIntAverage("HeightInInches");
.
.
.
Then have linq code to calculate the result.
Thanks!
I have created this little example, it uses the System.Linq.Expression namespace to create a function that can calculate averages based on the property name. The function can be cached for later use, reflection is only used to create the function, not each time the function is executed.
EDIT: I removed the existing reflection example and updated the current example to show the ability to walk a list of properties.
static class Program
{
static void Main()
{
var people = new List<Person>();
for (var i = 0; i < 1000000; i++)
{
var person = new Person { Age = i };
person.Details.Height = i;
person.Details.Name = i.ToString();
people.Add(person);
}
var averageAgeFunction = CreateIntegerAverageFunction<Person>("Age");
var averageHeightFunction = CreateIntegerAverageFunction<Person>("Details.Height");
var averageNameLengthFunction = CreateIntegerAverageFunction<Person>("Details.Name.Length");
Console.WriteLine(averageAgeFunction(people));
Console.WriteLine(averageHeightFunction(people));
Console.WriteLine(averageNameLengthFunction(people));
}
public static Func<IEnumerable<T>, double> CreateIntegerAverageFunction<T>(string property)
{
var type = typeof(T);
var properties = property.Split('.'); // Split the properties
ParameterExpression parameterExpression = Expression.Parameter(typeof(T));
Expression expression = parameterExpression;
// Iterrate over the properties creating an expression that will get the property value
for (int i = 0; i < properties.Length; i++)
{
var propertyInfo = type.GetProperty(properties[i]);
expression = Expression.Property(expression, propertyInfo); // Use the result from the previous expression as the instance to get the next property from
type = propertyInfo.PropertyType;
}
// Ensure that the last property in the sequence is an integer
if (type.Equals(typeof(int)))
{
var func = Expression.Lambda<Func<T, int>>(expression, parameterExpression).Compile();
return c => c.Average(func);
}
throw new Exception();
}
}
public class Person
{
private readonly Detials _details = new Detials();
public int Age { get; set; }
public Detials Details { get { return _details; } }
}
public class Detials
{
public int Height { get; set; }
public string Name { get; set; }
}
Here is an example to do that.
class Survey
{
public int P1 { get; set; }
}
class MyObject
{
readonly List<Survey> _listofSurveys = new List<Survey> { new Survey { P1 = 10 }, new Survey { P1 = 20 } };
public int GetIntAverage(string propertyName)
{
var type = typeof(Survey);
var property = type.GetProperty(propertyName);
return (int)_listofSurveys.Select(x => (int) property.GetValue(x,null)).Average();
}
}
static void Main(string[] args)
{
var myObject = new MyObject();
Console.WriteLine(myObject.GetIntAverage("P1"));
Console.ReadKey();
}
if you are using linq2sql i would suggest DynamicLinq
you could then just do
datacontext.Surveys.Average<double>("propertyName");
the dynamic linq project provides the string overloads to IQueryable.
You can do this without reflection (both int and double are supported):
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, int> selector)
{
return surveys.Average(selector);
}
public static double Average(this IEnumerable<Survey> surveys, Func<Survey, double> selector)
{
return surveys.Average(selector);
}
Usage:
var average1 = surveys.Average(survey => survey.Property1);
var average2 = surveys.Average(survey => survey.Property2);