Skip to content

Hierarchy implementation and fixes#215

Open
Xriuk wants to merge 3 commits into
EFNext:masterfrom
Xriuk:master
Open

Hierarchy implementation and fixes#215
Xriuk wants to merge 3 commits into
EFNext:masterfrom
Xriuk:master

Conversation

@Xriuk

@Xriuk Xriuk commented Jun 15, 2026

Copy link
Copy Markdown

Closes #74 and #213

I have added support for hierarchies where overwritten members are all added in the parent body with type casts, this is to match the runtime behaviour for generated expressions.

I have also allowed members tagged with [Projectable] to not have any body at all (abstract method/property) if they have at least one implemented member in derived classes.

I have added some tests, maybe not 100% of cases are covered, currently I'm not sure if any sub-hierarchies would be better flattened or not, eg:
A hierarchy like this:

public class A{
  [Projectable]
  public virtual int Id => 1;
}

public class B1 : A{
  [Projectable]
  public virtual int Id => 2;
}
public class B2 : B1{
  public virtual int Id => 3;
}

public class C : A{
  public virtual int Id => 4;
}

will generate a final Expression like this (the nested B1 expression gets replaced later):

@this => @this is B1 ? (@this is B2 ? ((B2)@this).Id : 2) : @this is C ? ((C)@this).Id : 1

And I'm not sure if it would be better to generate a flat expression like this instead (by associating the condition for B1 to the last else), or if this is something already handled by EF Core:

@this => @this is B2 ? ((B2)@this).Id : @this is B1 ? 2 : @this is C ? ((C)@this).Id : 1

I am open to any coding-style changes which might be required, also if everything seems good so far I could edit the docs to reflect the new changes.

@Xriuk Xriuk marked this pull request as draft June 16, 2026 08:50
@Xriuk

Xriuk commented Jun 16, 2026

Copy link
Copy Markdown
Author

I have some doubts about base.MyMethod() getting rewritten to @this.MyMethod(), the two invocations are not equivalent (one is the parent method, and one is the projected one), and would actually get to a loop of expressions getting replaced.

I would replace it with a cast like this ((BaseType)@this).MyMethod() and if the parent method is projected as well (like in my hierarchy implementation) I would replace it with just the method body instead of the full if/else if/else type chain.

So I would generate two expressions for each member in a hierarchy: one for the public invocations, and one for invocations from derived classes to avoid loops.

@Xriuk

Xriuk commented Jun 17, 2026

Copy link
Copy Markdown
Author

Also closes #213

I have rewritten base.MyMethod() to be translated to ((BaseType)@this).MyMethod() so that explicit invocations can be recognized and replaced later. Currently it should not change existing implementations, since a cast is usually ignored, but this could be replaced at the end if needed by removing the cast entirely after all the hierarchy replacements.

I am now generating 2 expressions for hierarchies: one "complete" which has all the typecasts and derived classes invocations, and one "base" which is used when replacing base.MyMethod() inside derived classes to avoid loops.

The "base" expressions currently do not have an assembly registry generated like regular expressions.

@Xriuk Xriuk marked this pull request as ready for review June 17, 2026 12:25
@Xriuk Xriuk changed the title Hierarchy implementation Hierarchy implementation and fixes Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Overriden property not getting used

1 participant