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);
}
}
Related
I have a class with a bunch of properties:
class Foo {
public string Name {get; set; }
public int Age {get; set;
}
and a collection of instances of Foo.
Now I want to order those elements by a property given by the user. So the user selects a property from the type Foo. Now I want to order by elements based on this property.
One approach is a reflection-based one similar to this:
var p = typeof(Foo).GetProperty("Age");
var ordered = fooList.OrderBy(x => (int) p.GetValue(x, null));
This works so far. However I also tried a second one and there I am stuck. It deals by performing an expression-tree as follows:
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f)
With
Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property).Compile();
}
My question is: As I should return a Func<T, int> where to get the int-part from or in other words where and how do I perform the actual comparison? I suppose I have to make a CallExpression to IComparable.CompareTo but I´m not sure how to do so. I think I need access to the both instances to compare.
EDIT: Complete code-example
static void Main()
{
var fooList = new[] { new Foo("Hans", 10), new Foo("Georg", 12), new Foo("Birgit", 40) };
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f);
}
private static Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property).Compile();
}
Executing this code will throw an
ArgumentException: Incorrect number of parameters supplied for lambda
declaration
The problem is that you're trying to build a Func<T, int> but your call to Expression.Lambda doesn't specify the parameter expression, which means you can't expect it to create a delegate that has any parameters. Just specifying type as a second argument to Expression.Lambda works. Here's a complete example based on your question - note that I've changed the ages to prove that it's actually ordering, and I've updated your fields to read-only properties:
using System;
using System.Linq;
using System.Linq.Expressions;
class Foo
{
public string Name { get; }
public int Age { get; }
public Foo(string name, int age)
{
this.Name = name;
this.Age = age;
}
}
class Test
{
static void Main()
{
var fooList = new[]
{
new Foo("Hans", 12),
new Foo("Georg", 10),
new Foo("Birgit", 40)
};
var f = GetOrderStatement<Foo>("Age");
var ordered = fooList.OrderBy(f);
foreach (var item in ordered)
{
Console.WriteLine($"{item.Name}: {item.Age}");
}
}
private static Func<T, int> GetOrderStatement<T>(string attrName)
{
var type = Expression.Parameter(typeof(T), attrName);
var property = Expression.PropertyOrField(type, attrName);
return Expression.Lambda<Func<T, int>>(property, type).Compile();
}
}
Output:
Georg: 10
Hans: 12
Birgit: 40
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; }
}
I have a sorted list that will pass in two elements and compare the two. Is there a function in the SortedList class in C# that will do a next and previous? I got some help with a .Skip, but since the keys would be variable, how would that work? All I need to do is take in the first element and second element, then skip to the third and fourth, fifth and sixth, etc. I wish it were as simple as LinkedList's ".next.next."
double velocity = positionList.Values.Skip(1);
Edit: The positionList is type
<double, HandCoordinate>
HandCoordinate = {double, double, double}
Does that help?
Thanks!
The class SortedList inherites IEnumerator, so you can use it:
SortedList list = ...
var listEnumerator = ((IEnumerable)list).GetEnumerator();
Pair<MyType> pair = null
do
{
pair = Pair.Next<MyType>(listEnumerator);
...
}
while(pair != null)
...
class Pair<T>
{
public T First {get; set;}
public T Second {get; set;}
public static Pair<T> Next<T>(IEnumerator enumerator)
{
var first = enumerator.Current;
if(enumerator.MoveNext())
{
return new Pair<T>
{
First = (T)first,
Second = (T)enumerator.Current,
}
}
return null;
}
}
List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);
ints.Add(3);
ints.Add(4);
for (int i = 0; i < ints.Count; i += 2)
{
var pair = ints.Skip(i).Take(2);
var first = pair.First();
var last = pair.Last();
}
Note: This should work, irrelevant of the type in theory. Unless the type is a drastically different format.
Without Skip().
var pair = new { First = ints[i], Second = ints[i += 1] };
The question is somewhat unclear. I'm assuming you need to get pairs of things from a list?
It's fairly easy to write an extension method that will present a sequence of pairs of items from an IEnumerable:
using System;
using System.Collections.Generic;
namespace Demo
{
internal static class Program
{
public static void Main()
{
double[] test = new double[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foreach (var pair in test.AsPairs()) // This is how you use it.
{
Console.WriteLine("({0}, {1})", pair.Item1, pair.Item2);
// Or simply: Console.WriteLine(pair);
}
}
}
public static class EnumerableExt
{
public static IEnumerable<Tuple<T, T>> AsPairs<T>(this IEnumerable<T> sequence)
{
bool isFirst = true;
T first = default(T);
foreach (var item in sequence)
{
if (isFirst)
{
first = item;
isFirst = false;
}
else
{
isFirst = true;
yield return new Tuple<T, T>(first, item);
}
}
}
}
}
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);
}
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));