1

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:

  • SomeExpression has to be defined on the entity instance e
  • SomeExpression has to operate on e (I am thinking of Expression.Consntant(this))
  • SomeExpression has to be supported by EntityFramework
  • SomeExpression has to return generic value, e.g. string or int

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.

6
  • "not really", however: expression trees are very powerful and flexible (and can be constructed in several ways) - if you can give a more complete example of why you want to do this (i.e. a scenario in which it would be useful), it is almost certainly possible to get it to do what you want in some way. Commented Nov 16, 2018 at 11:58
  • @MarcGravell thanks. I have edited the question to provide context. Commented Nov 16, 2018 at 13:21
  • 1
    The problem is that when you do Select(e => e.Whatever()), Whatever is not called, but simply "marked" as MethodCall inside 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 LinqKit AsExoandable and NeinLinq ToInjectable do. Commented Nov 16, 2018 at 13:53
  • @IvanStoev I see. I've looked at LinqKit, but its not all around solid solution, unfortunately. It would be fine inside services, but if I use Invoke in the view-model mapping, I have no way of guaranteeing that AsExpandable is called on the query, before the mapping. Essentially an invitation for runtime exceptions. Commented Nov 16, 2018 at 14:15
  • You are using 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 do e.(an Expression) or (an Expression)(). Commented Nov 16, 2018 at 20:46

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.