Lambda expression casting - c#

How can I cast from
Expression<Func<T, bool>> predicate
to
Expression<Func<SomeType, bool>> predicate
?
Couldn't find a way so far. Or at least create a new Expression<Func<SomeType, bool>> by using the first one's string representation of the predicate.
If it helps, T is limited to types implementing ISomeInterface, and SomeType implements it.
LE: further clarification
The interface is something like:
public interface ICacheable
{
List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable;
}
then you have
public partial class Video : ICacheable
{
public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
// implementation here that returns the actual List<Video>
// but when I try to query the dbcontext I can't pass a predicate with type T, I have to cast it somehow
List<Video> videos = db.Videos.Where(predicate).ToList(); // not working
}
}
then you have:
public class RedisCache
{
public List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
List<T> objList = // get objects from cache store here
if(objList == null)
{
List<T> objList = GetObjects<T>(predicate);
// cache the result next
}
return objList;
}
}
I use the above from any class like so:
// If the list is not found, the cache store automatically retrieves
// and caches the data based on the methods enforced by the interface
// The overall structure and logic has more to it.
List<Video> videos = redisCache.GetList<Video>(v => v.Title.Contains("some text"));
List<Image> images = redisCache.GetList<Image>(v => v.Title.Contains("another text"));
And I would extend this to any type of object I need to be cachable, with methods that will allow the Cache store to automatically retrieve an entity or list of entities if they are not found in cache. I might be doing this completely wrong though.

I'm not up to scratch on my Entity Framework, but I know that the DatabaseContext within LINQ has a GetTable<T> which returns the table based on the generic. If "GetTable equivalent for ObjectContext" is anything to go by, it's also available in EF?
To make your statement truly generic, you could try this:
public MyBaseObject<T>
{
public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
{
return db.CreateObjectSet<T>().Where(predicate).ToList();
}
}
public partial class Image : MyBaseObject<Image>, ICacheable
{
}
public partial class Video : MyBaseObject<Video>, ICacheable
{
}

Here is something (extremely) basic which, I hope, might help you in the process of caching using generics.
// ICacheable interface is used as a flag for cacheable classes
public interface ICacheable
{
}
// Videos and Images are ICacheable
public class Video : ICacheable
{
public String Title { get; set; }
}
public class Image : ICacheable
{
public String Title { get; set; }
}
// CacheStore will keep all objects loaded for a class,
// as well as the hashcodes of the predicates used to load these objects
public class CacheStore<T> where T : ICacheable
{
static List<T> loadedObjects = new List<T>();
static List<int> loadedPredicatesHashCodes = new List<int>();
public static List<T> GetObjects(Expression<Func<T, bool>> predicate)
{
if (loadedPredicatesHashCodes.Contains(predicate.GetHashCode<T>()))
// objects corresponding to this predicate are in the cache, filter all cached objects with predicate
return loadedObjects.Where(predicate.Compile()).ToList();
else
return null;
}
// Store objects in the cache, as well as the predicates used to load them
public static void StoreObjects(List<T> objects, Expression<Func<T, bool>> predicate)
{
var hashCode = predicate.GetHashCode<T>();
if (!loadedPredicatesHashCodes.Contains(hashCode))
{
loadedPredicatesHashCodes.Add(hashCode);
loadedObjects = loadedObjects.Union(objects).ToList();
}
}
}
// DbLoader for objets of a given class
public class DbStore<T> where T : ICacheable
{
public static List<T> GetDbObjects(Expression<Func<T, bool>> predicate)
{
return new List<T>(); // in real life, load objects from Db, with predicate
}
}
// your redis cache
public class RedisCache
{
public static List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T:ICacheable
{
// try to load from cache
var objList = CacheStore<T>.GetObjects(predicate);
if(objList == null)
{
// cache does not contains objects, load from db
objList = DbStore<T>.GetDbObjects(predicate);
// store in cache
CacheStore<T>.StoreObjects(objList,predicate);
}
return objList;
}
}
// example of using cache
public class useRedisCache
{
List<Video> videos = RedisCache.GetList<Video>(v => v.Title.Contains("some text"));
List<Image> images = RedisCache.GetList<Image>(i => i.Title.Contains("another text"));
}
// utility for serializing a predicate and get a hashcode (might be useless, depending on .Equals result on two equivalent predicates)
public static class PredicateSerializer
{
public static int GetHashCode<T>(this Expression<Func<T, bool>> predicate) where T : ICacheable
{
var serializer = new XmlSerializer(typeof(Expression<Func<T, bool>>));
var strw = new StringWriter();
var sw = XmlWriter.Create(strw);
serializer.Serialize(sw, predicate);
sw.Close();
return strw.ToString().GetHashCode();
}
}

Related

Ordeby(), Where(), etc. used in a function with generic types

I am currently fiddling with generic repositories. My test application is in C#. I have made a function that prints out all items in particular repository. A repository is an input parameter. The whole block is at the bottom of this post and currently the function itself looks like this:
static void PrintCollection<T, TKey>(IRepository<T, TKey> repo)
{
// Error since compiler does not recognizes p.LastName
//foreach (Person p in repo.GetItems().OrderBy(p => p.LastName)) Console.WriteLine(Convert.ToString(p));
foreach (T p in repo.GetItems())
Console.WriteLine(Convert.ToString(p));
}
It's working fine but it's missing things like ordering by particular property in a class, such as LastName in Person or ProductName in Product. I was wondering if it's possible to send an extra parameter to PrintCollection<T, TKey>(...) and test whether the particular field exists and then order by it. For instance:
static void PrintCollection<T, TKey, TOrder>(IRepository<T, TKey> repo, TOrder o = default(TOrder))
{
if (o == default(TOrder))
foreach (T p in repo.GetItems()) Console.WriteLine(Convert.ToString(p));
else
// Order by o
}
At the moment, I don't know what I should use to test the fields and properties against their existance in a class. And then, how to use them in LINQ and Lambdsa Expression to e.g. order, sort, filter collections.
Thanks
Below is a snippet of my code. I cut out unimportant parts.
Main program
class Program
{
static void Main(string[] args)
{
PeopleRepository repPeople = new PeopleRepository();
ProductsRepository repProduct = new ProductsRepository();
PrintCollection(repPeople);
PrintCollection(repProduct);
}
static void PrintCollection<T, TKey>(IRepository<T, TKey> repo)
{
// Error since compiler does not recognizes p.LastName
//foreach (Person p in repo.GetItems().OrderBy(p => p.LastName)) Console.WriteLine(Convert.ToString(p));
foreach (T p in repo.GetItems()) Console.WriteLine(Convert.ToString(p));
}
}
Interface IRepository
interface IRepository<T, TKey>
{
IEnumerable<T> GetItems();
T GetItem(TKey key);
// ...
}
Repository for People
class PeopleRepository : IRepository<Person, string>
{
private static List<Person> _proxy;
public PeopleRepository(List<Person> people = null)
{
if(people == null) _proxy = Person.GetAllPeople();
else _proxy = people;
}
public IEnumerable<Person> GetItems()
{
return _proxy;
}
public Person GetItem(string key)
{
return _proxy.SingleOrDefault(p => p.ID == key);
}
}
Repository for Products
class ProductsRepository : IRepository<Product, int>
{
private static List<Product> _proxy;
public ProductsRepository(List<Product> products = null)
{
if (products == null) _proxy = Product.GetAllProducts();
else _proxy = products;
}
public IEnumerable<Product> GetItems()
{
return _proxy;
}
public Product GetItem(int key)
{
return _proxy.SingleOrDefault(p => p.ID == key);
}
}
Yes, you can, using delegate for selecting order by clause:
static void PrintCollection<T, TKey, TOrder>(IRepository<T, TKey> repo,
Func<T,TOrder> orderBy)
{
var items = repo.GetItems();
if (orderBy != null)
items = items.OrderBy(orderBy);
foreach (T p in items)
Console.WriteLine(Convert.ToString(p));
}
you can call it like:
PrintCollection(repo, x=>x.Name);
For Where you need argument of type Func<T,bool> and the process is the same as above.
Note: If you use ORM like EF, the ORMs need entire expression tree in order to build the SQL statement for the query. As we pass a delegate, so the ordering or filtering does not translate to SQL. The ORM loads the data then applies ordering or filtering on it.
If you want to make sure they translate to SQL, the return type must be of type that implements IQueryable and the parameters for the function should change to Expression<Func<T,TOrder>> for orderBy and Expression<Func<T,bool>> for while.
Suggestion
Define this method as extension for IEnumerable :
public static class IEnumerableExtenstions
{
static void PrintCollection<T>(this IEnumerable<T> collection)
{
foreach (T p in collection)
Console.WriteLine(Convert.ToString(p));
}
}
and then you can call it like:
repo.GetItems().Where(x=>x.Age>15).OrderBy(x=>x.Name).PrintCollection();
which is more flexible and natural than defining parameters for each functionality in the function.

Any significant reason to avoid `as IQueryable`?

I have a library of model-to-viewmodel mapping extension methods. Supporting them is a base class with a few common methods, including Transform, below:
internal abstract class TransformBase<TOriginal, TConverted>
{
protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }
public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
{
var queryable = value as IQueryable<TOriginal> ?? value.AsQueryable();
return queryable.Select(Expression);
}
My question: is there any significant reason, besides a negligible performance hit, that I should avoid the as IQueryable cast above? For example, I could instead do the following:
internal abstract class TransformBase<TOriginal, TConverted>
{
protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }
public IQueryable<TConverted> Transform(IQueryable<TOriginal> value)
{
return value.Select(Expression);
}
public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
{
return value.AsQueryable().Select(Expression);
}
... but I would prefer not to have to write the overloads in every one of my dependent classes. EDIT: To clarify, here is an example of what I'm seeking to avoid:
public static class TransformCompany
{
private static readonly TransformBase<Organization, CompanyHeader> header = new TransformPrecompiled<Organization, CompanyHeader>(
company => new CompanyHeader
{
Name = company.Name,
});
public static IQueryable<CompanyHeader> AsHeaders(this IQueryable<Organization> companies)
{
return header.Transform(companies);
}
// Note I have to include this capability in each of my dependent classes
// Worse is the possibility that someone may accidentally implement
// only IEnumerable for a future model transformation,
// causing a hidden data performance problem
public static IQueryable<CompanyHeader> AsHeaders(this IEnumerable<Organization> companies)
{
return header.Transform(companies);
}
I would say you do not need separate extensions for IEnumerable<T> and IQueryable<T> as IQueryable<T> inherits from IEnumerable<T>, and you also do not need to the cast.
Looking at referencesource, AsQueryable() actually does this check for you:
public static IQueryable<TElement> AsQueryable<TElement>(this IEnumerable<TElement> source)
{
if (source == null)
throw Error.ArgumentNull("source");
if (source is IQueryable<TElement>)
return (IQueryable<TElement>)source;
return new EnumerableQuery<TElement>(source);
}
Therefore the following should work for you with no performance hit:
internal abstract class TransformBase<TOriginal, TConverted>
{
protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }
public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
{
return value.AsQueryable().Select(Expression);
}
}
public static class TransformCompany
{
public static IQueryable<CompanyHeader> AsHeaders(this IEnumerable<Organization> companies)
{
return header.Transform(companies);
}
}
Queryable.AsQueryable Method (IEnumerable)
If the type of source implements IQueryable,
AsQueryable(IEnumerable) returns it directly. Otherwise, it returns an
IQueryable that executes queries by calling the equivalent query
operator methods in Enumerable instead of those in Queryable.
Instead of casting you simplify your Transform method to
return value.AsQueryable().Select(Expression);

Query over interface properties using EntityFramework and LinqKit

I'm using EntityFramework and LinqKit to build expressions trees which get translated into SQL. Also we use the specification pattern to organize our queries.
There is a need in almost all of our domain objects to execute a query by description, but in some of those classes the property is called "Name", in others "Description", etc.
So initially was defined a interface as follow:
public interface IDescritible
{
string Description { get; }
}
The problem appeared when I tried to use it implemented explicitly in a class and made a generic query upon that:
public class Foo : IDescritible
{
public string Name { get; set; }
string IDescritible.Description
{
get { return this.Name; }
}
}
public class DescriptionMatch<T> : AbstractSpecification<T>
where T : IDescritible
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
return x => x.Description.Contains(Query);
}
}
When run, the EntityFramework is unable to translate the property get (a method call) into a SQL expression.
Then I tried to define a Expression in the class as follows:
public interface IDescritible<T> where T: IDescritible<T>
{
Expression<Func<T, string>> DescriptionExpression { get; }
}
public class Foo : IDescritible<Foo>
{
public string Name { get; set; }
public Expression<Func<Foo, string>> DescriptionExpression
{
get { return x => x.Name; }
}
}
public class DescriptionMatch<T> : AbstractSpecification<T> where T : IDescritible<T>
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
Expression<Func<T, bool>> combinedExpression = x => x.DescriptionExpression.Invoke(x).Contains(this.Query);
return combinedExpression.Expand();
}
}
But when it executes the .Expand() a exception is thrown: Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.LambdaExpression'.
Then I found out that LinqKit only support expanding local defined expressions (as stated on this question) and that there are some unoficial code write to solve those issues (answers on this question).
But when I modified the LinqKit library to try either one of the proposed solutions in second question it started to throw: variable 'x' of type 'Foo' referenced from scope '', but it is not defined.
Maybe that was caused by the fact that I don't have a instance of Foo yet? Only got the generic type parameter, and that's why I can't define my expression on a local variable. Maybe there is a way to define as a static expression somehow "attached" into class? But then I would not be able to use it in a generic query, there will be no interface...
There is a way to modify LinqKit so I can build expressions defined on a explicit implementation of a interface? Or there is another way to make a generic query upon properties explicitly implemented? Or any other solution or things to look into?
There is no need to use neither LinqKit or specification pattern for that, but EntityFramework is mandatory, what is important is to have a interface/any other way that support "pointing out" which property is the description property and make a generic Expression upon that.
Thank you in advance!
The easiest way to do it is to make the following change
public class DescriptionMatch<T> : AbstractSpecification<T> where T : IDescritible<T>, new()
Then you can get an instance by simply newing up a T (which EF), using the expression and otherwise discarding the object
public interface IDescritible<T> where T : IDescritible<T>
{
Expression<Func<T, string>> DescriptionExpression { get; }
}
public class Foo : IDescritible<Foo>
{
public string Name { get; set; }
public Expression<Func<Foo, string>> DescriptionExpression
{
get { return x => x.Name; }
}
}
public abstract class AbstractSpecification<T>
{
public abstract Expression<Func<T, bool>> IsSatisfiedBy();
}
public class DescriptionMatch<T> : AbstractSpecification<T>
where T : IDescritible<T>, new()
{
public string Query { get; set; }
public DescriptionMatch(string query)
{
this.Query = query;
}
public override Expression<Func<T, bool>> IsSatisfiedBy()
{
Expression<Func<T, string>> lambda = new T().DescriptionExpression;
return Expression.Lambda<Func<T, bool>>(
Expression.Call(
lambda.Body,
"Contains",
Type.EmptyTypes,
Expression.Constant(
this.Query,
typeof(string)
)
),
lambda.Parameters
);
}
}
public class ExpressionReplacer : ExpressionVisitor
{
private readonly Expression _toBeReplaced;
private readonly Expression _replacement;
public ExpressionReplacer(Expression toBeReplaced, Expression replacement)
{
if (toBeReplaced.Type != replacement.Type)
{
throw new ArgumentException();
}
this._toBeReplaced = toBeReplaced;
this._replacement = replacement;
}
public override Expression Visit(Expression node)
{
return Object.ReferenceEquals(node, this._toBeReplaced) ? this._replacement : base.Visit(node);
}
}

Creating generic Expression

I have a problem regarding generic expressions.
I have an Expression<Func<T, bool>> and I want to convert the Expression<Func<T, bool>> to Expression<Func<Y, bool>>. The object of class T has the same properties as the class Y.
Does anybody know how to solve this?
The "preferred" way to do this is use a Interface that contains the property you care about.
interface IMyProp
{
string SomeProp {get;}
}
class T : IMyProp
{
public string SomeProp
{
get
{
//Some complicated logic
}
}
}
class Y : IMyProp
{
public string SomeProp {get; set;}
}
The just code your expression to Expression<Func<IMyProp, bool>>
However it is understandable that you can not always do this, for situations like this you can use a library like AutoMapper
class T
{
public string SomeProp
{
get
{
//Some complicated logic
}
}
}
class Y
{
public string SomeProp {get; set;}
}
//Some initiation code somewhere else in your project
public static void InitializeMappings()
{
Mapper.CreateMap<T, Y>();
}
public static IQueryable<Y> FilterOnTAndMapToY(IQueryable<T> source, Expression<Func<T,bool>> filter)
{
return source.Where(filter).Project().To<Y>();
}
Now this does not exactly turn your Expression<Func<T, bool>> in to a to Expression<Func<Y, bool>> but it does let you use your T expression and use it to get a Y result after the filtering has been applied.
The way AutoMapper's Queryable Extensions work is the querys and casts to go from T to Y happen all server side when you are doing LinqToEntities. So you could even do
public static IQueryable<Y> MultiFilterCast(IQueryable<T> source, Expression<Func<T,bool>> tTypeFilter, Expression<Func<Y,bool>> yTypeFilter)
{
var filteredStage1 = source.Where(tTypeFilter);
var castToY = filteredStage1.Project().To<Y>();
var filteredStage2 = castToY.Where(yTypeFilter);
return filteredStage2;
}
both tTypeFilter and yTypeFilter will be applied server side before you get the result set.

C# generic constraint not working as expected

I have a situation where I need to dynamically build up a list of filters to apply to a list of objects. Those objects can be anything that implements an interface which contains all of the properties I need to filter on.
public interface IStuff
{
bool SuitableForSomething { get; set; }
bool SuitableForSomethingElse { get; set; }
}
public class SomeStuff : IStuff
{
...
}
public class SomeOtherStuff : IStuff
{
...
}
I have a list of criteria defined like so ...
public List<Expression<Func<IStuff, bool>>> Criteria { get; private set; }
and add criteria like so ...
Criteria.Add(x => x.SuitableForSomething);
Criteria.Add(x => x.SuitableForSomethingElse);
I then apply the criteria to my query like so ...
var stuff= _stuffCache
.GetAll()
.AsQueryable()
.ApplyCriteria(Criteria);
which uses the following extension method ...
public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<IStuff, bool>>> criteria)
where T : IStuff
{
foreach (var expression in criteria)
{
stuff = Queryable.Where(stuff, expression);
}
return stuff;
}
The compiler is telling me ...
cannot convert from
'System.Linq.Expressions.Expression<System.Func<IStuff,bool>>'
to
'System.Linq.Expressions.Expression<System.Func<T,int,bool>>'
When I hover over the red line under the error in the IDE it's saying it cannot resolve method between
IQueryable<IStuff> Where<IStuff>(this IQueryable<IStuff>, Expression<Func<IStuff, bool>>) in class Queryable
and
IQueryable<T> Where<T>(this IQueryable<T>, Expression<Func<T,int,bool>>) in class Queryable
If I try casting the expression to Expression<Func<T, bool>>, which ought to work as T is constrained to implement the IStuff interface. I get
Cannot cast expression of type 'Expression<Func<IStuff, bool>>' to type 'Expression<Func<T, bool>>'
EDIT
Thanks to Raphaƫl's answer I fixed the extension method and eventually found the real problem I had, which was a casting problem when I was calling the code. Easily fixed by adding a .Cast<SomeStuff>() after the ApplyCriteria call.
Before
var stuff= _stuffCache
.GetAll()
.AsQueryable()
.ApplyCriteria(Criteria);
After
var stuff= _stuffCache
.GetAll()
.AsQueryable()
.ApplyCriteria(Criteria)
.Cast<SomeStuff>();
change second parameter type to List<Expression<Func<T,bool>>> (T instead of IStuff)
public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<T, bool>>> criteria)
where T : IStuff
{
foreach (var expression in criteria)
{
stuff = Queryable.Where(stuff, expression);
//or stuff = stuff.Where(expression), as Where is an Extension method;
}
return stuff;
}
and your method can be (thx resharper), rewritten to
public static IQueryable<T> ApplyCriteria<T>(this IQueryable<T> stuff, List<Expression<Func<T, bool>>> criteria)
where T : IStuff
{
return criteria.Aggregate(stuff, (current, expression) => current.Where(expression));
}

Categories