EF Core Projectables supports abstract/virtual/overwritten properties and methods decorated with [Projectable], and can generate expression trees to mimic virtual calls.
Virtual members are invoked for the most-specific type of the instance.
public class Foo{
public virtual string Name() => "Foo";
}
public class Bar : Foo{
public override string Name() => "Bar";
}
var bar = new Bar();
bar.Name(); // "Bar"Expressions are compiled and cannot know which type the provided instance will be, so the only solution is a type test chain, which gets automatically created.
public class Foo{
[Projectable(PolymorphicDispatch = true)]
public virtual string Name() => "Foo";
// Converted to: @this is Bar ? "Bar" : "Foo"
}
public class Bar : Foo{
[Projectable(PolymorphicDispatch = true)]
public override string Name() => "Bar";
// Converted to: "Bar" as it has no derived types
}Members can also be abstract, in which case the last branch of the type test chain will just be the last type itself.
public abstract class Foo{
[Projectable(PolymorphicDispatch = true)]
public abstract string Name();
// Converted to: @this is Bar ? "Bar" : "Baz"
}
public class Bar : Foo{
[Projectable(PolymorphicDispatch = true)]
public override string Name() => "Bar";
// Converted to: "Bar" as it has no derived types
}
public class Baz : Foo{
[Projectable(PolymorphicDispatch = true)]
public override string Name() => "Baz";
// Converted to: "Baz" as it has no derived types
}You can also use base in your derived types to invoke the base method/property.
public class Foo{
[Projectable(PolymorphicDispatch = true)]
public virtual string Name() => "Foo";
// Converted to: @this is Bar ? (((Bar)@this).MyProp ? "Bar" : "Foo") : "Foo"
}
public class Bar : Foo{
public bool MyProp { get; set; }
[Projectable(PolymorphicDispatch = true)]
public override string Name() => MyProp ? "Bar" : base.Name();
// Converted to: @this.MyProp ? "Bar" : "Foo" as it has no derived types
}Add PolymorphicDispatch = true to the Projectables