As stated by the title - I want to define an expression, which describes only the body of a method. Example:
// Definition
public Expression<T> SomeExpression<T>() { ... }
// Usage
entities.Select(e => e.SomeExpression<int>())
// Instead of
entities.Select(SomeExpression<int>())
I know I can define a delegate Expression as
Expression<Func<int>> SomeExpression() { ... }
But since this describes a full-fat delegate I have to use it as .Select(SomeExpression()). This is a problem, because the only way I can seamlessly use it is to attach SomeExpression on the entity instance itself.
I know this makes little sense - in short, I am trying to implement a workaround for a stupid mistake made long ago in the project. Proper fix is out of the question.
Remarks:
SomeExpressionhas to be defined on the entity instanceeSomeExpressionhas to operate one(I am thinking ofExpression.Consntant(this))SomeExpressionhas to be supported by EntityFrameworkSomeExpressionhas to return generic value, e.g.stringorint
More information
I am trying to solve a poor inheritence issue - I have an entity (Training), which has foreign key to another entity (Course). The training entity is composed of a base class(of the same name - Training) and several derived ones (Instances). The problem is that the foreign key, which is absolutely identical for all, is held in a property of the derived classes, instead of the base one. Since I have a common layer of services, every time I get a Training entity i have to perform several conditional casts to all of the derived classes, to get to the Course entity.
SomeExpression itself effectively translates to something like
t => t is InternalInstance
? (t as InternalInstance).Course,
: t is OpenInstance
? // So on an so forth...
You can read in more details in this topic.
Why wouldn't a lambda work in my case? I have omitted generics in the question, to keep it simple, however in my case SomeExpression and its class has to depend on several generic parameters, since I have several web projects in my solution, each coming with its own Course and Instance types.
That is why ideal place for this expression would be on the Training type - it already has the required generic parameters. If I don't put it there I have to create a service and use the container to resolve them. Then I would have to inject this service everywhere I want to use this mapping - mainly common services and view models. Adding it to the common services isn't a problem, but is obtrusive, as in you need additional dependency, just to perform the mapping. The view models are problematic, since they use AutoMapper configuration, to encapsulate the mapping and keep it inside. AutoMapper creates and caches the maps well before the container is up and running, which resolves in NullReference. There are ways to provide the service runtime, but that increases the boilerplate in both view model and controller. At this point using the expression to get Course is more of a hassle, then convenient.
That's the context. I tried to keep it short, but there are a lot of obstacles.
Select(e => e.Whatever()),Whateveris not called, but simply "marked" asMethodCallinside the expression tree. Which makes it non translatable, because EF translation is based on knowledge - any unknowns are simply exceptions (EF6) or client evaluation (EF Core). Shortly, even if you somehow solve the C# syntactical part, you can't solve the issue in general w/o expression tree post processing. Basically what LinqKitAsExoandableand NeinLinqToInjectabledo.Invokein the view-model mapping, I have no way of guaranteeing thatAsExpandableis called on the query, before the mapping. Essentially an invitation for runtime exceptions.Expressions in ways that aren't possible, making it hard for me to follow what you are trying to accomplish, e.g. you can't doe.(anExpression) or (anExpression)().