Giter Site home page Giter Site logo

hazzik / delegatedecompiler Goto Github PK

View Code? Open in Web Editor NEW
518.0 31.0 62.0 2.69 MB

A library which is able to decompile a delegate or a method body to its lambda representation

License: MIT License

C# 95.85% Batchfile 0.29% Visual Basic .NET 3.87%
decompile delegate lambda-representation entity-framework

delegatedecompiler's Introduction

DelegateDecompiler celebrates 10th year anniversary 🎂

https://ci.appveyor.com/project/hazzik/delegatedecompiler/branch/main https://nuget.org/packages/DelegateDecompiler

A library that is able to decompile a delegate or a method body to their lambda representation

Sponsorship

If you like the library please consider supporting my work.

Examples

Using computed properties in linq.

Asume we have a class with a computed property

class Employee
{
    [Computed]
    public string FullName => FirstName + " " + LastName;

    public string LastName { get; set; }

    public string FirstName { get; set; }
}

And you are going to query employees by their full names

var employees = (from employee in db.Employees
                 where employee.FullName == "Test User"
                 select employee).Decompile().ToList();

When you call .Decompile method it decompiles your computed properties to their underlying representation and the query will become simmilar to the following query

var employees = (from employee in db.Employees
                 where (employee.FirstName + " " + employee.LastName)  == "Test User"
                 select employee).ToList();

If your class doesn't have a [Computed] attribute, you can use the .Computed() extension method..

var employees = (from employee in db.Employees
                 where employee.FullName.Computed() == "Test User"
                 select employee).ToList();

Also, you can call methods that return a single item (Any, Count, First, Single, etc) as well as other methods in identical way like this:

bool exists = db.Employees.Decompile().Any(employee => employee.FullName == "Test User");

Again, the FullName property will be decompiled:

bool exists = db.Employees.Any(employee => (employee.FirstName + " " + employee.LastName) == "Test User");

Using with EntityFramework and other ORMs

If you are using ORM specific features, like EF's Include, AsNoTracking or NH's Fetch then Decompile method should be called after all ORM specific methods, otherwise it may not work. Ideally use Decompile extension method just before materialization methods such as ToList, ToArray, First, FirstOrDefault, Count, Any, and etc.

Async Support with EntityFramework 6

The DelegateDecompiler.EntityFramework package provides DecompileAsync extension method which adds support for EF's Async operations.

Async Support with EntityFramework Core 2.0-3.1

The DelegateDecompiler.EntityFrameworkCore package provides DecompileAsync extension method which adds support for EF's Async operations.

The DelegateDecompiler.EntityFrameworkCore5 package provides DecompileAsync extension method which adds support for EF's Async operations.

Installation

Available on NuGet

License

MIT license - http://opensource.org/licenses/mit

delegatedecompiler's People

Contributors

beewarloc avatar bensho avatar billybraga avatar bitdeli-chef avatar cervengoc avatar cmeyertons avatar daveaglick avatar dennisinsky avatar fimiki avatar giorgi avatar gvas avatar hazzik avatar jaenyph avatar jbogard avatar jonpsmith avatar magicmoux avatar mcintyre321 avatar otf avatar richardsinden avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

delegatedecompiler's Issues

DelegateDecompiler throws InvalidCastException on int? in combination with datetime?

DelegateDecompiler will crash with in InvalidCastException when using a combination of a Nullable Int and a Nullable DateTime. This will only happen in release mode.

I have created a testcase of which the code is down below, or you can download the entire project (console application) at http://www.clockwise-it.nl/DelegateDecompilerNullableDateTime.zip

  class Program
    {
        static void Main(string[] args)
        {
            var items = new List<TestClass1>();
            items.AsQueryable().Where(i => i.Test).Decompile();
        }

        public class TestClass1
        {
            public DateTime? NullableDate { get; set; }
            public int? NullableInt { get; set; }

            [Computed]
            public bool Test
            {
                get
                {
                    return NullableDate.HasValue && NullableInt.HasValue &&
                           NullableDate.Value.AddDays(NullableInt.Value) > DateTime.Now;
                }
            }
        }
    }

The DelegateDecompiler crashes at the following line:

 else if (instruction.OpCode == OpCodes.Stloc_S)
                {
                    StLoc((byte) instruction.Operand);
                }

Trying to cast a nullable int to a byte

Question on whether we should have .DecompileEf

Hi guys,

Did you see my question question/comment about name clash? It was in a issue that is now closed. See below:

I could imagine a situation where you need both the DelegateDecompiler namespace and the DelegateDecompiler.EntityFramework, at which point you get an 'ambiguous reference' compile error. Dave did suggest another name, like DecompileEf or something. Is it a good idea to change things now before people start using it??

I happy to go with whatever you guys think, but an 'ambiguous reference' on an extension method is a bit harder to deal with.

ArgumentException when the Computed Expression Body has a call to a method passing an enum value

When the computed expression body has a call to a method that takes an enum as an argument, an invalid operation exception is thrown because it tries to pass the integer value instead of the typed enum one.

Here is a repro:

public class Foo
{
    public Decimal Value { get; set; }

    [Computed]
    public Decimal RoundedValue
    {
        get
        {
            return Decimal.Round(Value, 3, MidpointRounding.AwayFromZero);
        }
    }
}

public void Should_be_able_to_decompile_the_rounded_value()
{
    var roundedValues = Enumerable.Range(1,10)
                                    .Select(x => new Foo {Value =123.4561m})
                                    .AsQueryable()
                                    .Select(x => x.RoundedValue)
                                    .Decompile();

    roundedValues.Distinct().Count().ShouldBe(2);
    roundedValues.ShouldContain(123.456m);
    roundedValues.ShouldContain(123.457m);
}

The test above fails with the following Exception:

System.ArgumentException
    Expression of type 'System.Int32' cannot be used for parameter of type 'System.MidpointRounding' of method 'System.Decimal Round(System.Decimal, Int32, System.MidpointRounding)'   
    at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
    at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
    at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
    at DelegateDecompiler.Processor.BuildMethodCallExpression(MethodInfo m, Address instance, Expression[] arguments)
    at DelegateDecompiler.Processor.Call(ProcessorState state, MethodInfo m)
    at DelegateDecompiler.Processor.Process()
    at DelegateDecompiler.Processor.Process(VariableInfo[] locals, IList`1 args, Instruction instruction, Type returnType)
    at DelegateDecompiler.MethodBodyDecompiler.Decompile()
    at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass1.<Decompile>b__0(MethodInfo m)
    at DelegateDecompiler.Cache`2.GetOrAdd(TKey key, Func`2 func)
    at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method)
    at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments)
    at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
    at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
    at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
    at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
    at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
    at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
    at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
    at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
    at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
    at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
    at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
    at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
    at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
    at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
    at DelegateDecompiler.DecompiledQueryProvider.CreateQuery[TElement](Expression expression)
    at DelegateDecompiler.DecompileExtensions.Decompile[T](IQueryable`1 self)

decompile error

        Dim oMeth As MethodInfo
        oMeth = oEventDelegate.GetInvocationList(0).Method
        Dim oL As Expressions.LambdaExpression
        oL = DelegateDecompiler.DecompileExtensions.Decompile(oMeth)

when i call DelegateDecompiler.DecompileExtensions.Decompile, i get this error only with this method....

{System.ArgumentException: Expression of type 'System.Void' cannot be used for parameter of type 'System.Exception' of method 'Void SetProjectError(System.Exception)'
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection1& arguments) at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable1 arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
at DelegateDecompiler.Processor.BuildMethodCallExpression(MethodInfo m, Expression instance, Expression[] arguments)
at DelegateDecompiler.Processor.Call(MethodInfo m)
at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last)
at DelegateDecompiler.Processor.Process(Instruction instruction, Type returnType)
at DelegateDecompiler.MethodBodyDecompiler.Decompile()
at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass1.b__0(MethodInfo m)
at DelegateDecompiler.Cache2.GetOrAdd(TKey key, Func2 func)
at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method)
at ODSYSNET.mVarious.isObjectIncludedInMethodOrEvent(Object oObject, String sMethodName, String sFindObject, Boolean isEvent)

..and this is my event method...

Private Sub ODForm_GRID_RowChanged(ByRef oGrd As ODSYSNET.CGrid) Handles ODForm.GRID_RowChanged

    Try
        Select Case oGrd.Name

            Case grdTransactions.Name
                If Not oGrd.SelectedRow Is Nothing Then
                    moInvoices.CommandSelect.CommandText.Where = "Idkp = " & Val(IfNull(oGrd.GetValue("TIMIDKP"), -1))
                    moInvoices.Load()
                End If
        End Select

    Catch ex As Exception
        ODShowErr(ex, , Me)
    End Try

End Sub

InvalidCastException when running in Release

I'm having a hard time replicating this one in a simple project or in the test suite, but I'm seeing lots of InvalidCastExceptions when running in a Release build. I have been able to reproduce this behavior in my larger application both locally and on a remote IIS server. I'll continue to try and narrow down the problem, but in the meantime, here's a stack trace:

DelegateDecompiler : System.InvalidCastException
Specified cast is not valid.

at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last)
at DelegateDecompiler.Processor.ConditionalBranch(Instruction instruction, Func2 condition) at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last) at DelegateDecompiler.Processor.ConditionalBranch(Instruction instruction, Func2 condition)
at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last)
at DelegateDecompiler.Processor.ConditionalBranch(Instruction instruction, Func2 condition) at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last) at DelegateDecompiler.Processor.ConditionalBranch(Instruction instruction, Func2 condition)
at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last)
at DelegateDecompiler.Processor.ConditionalBranch(Instruction instruction, Func2 condition) at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last) at DelegateDecompiler.Processor.Process(Instruction instruction, Type returnType) at DelegateDecompiler.MethodBodyDecompiler.Decompile() at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass1.<Decompile>b__0(MethodInfo m) at DelegateDecompiler.Cache2.GetOrAdd(TKey key, Func2 func) at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method) at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList1 arguments)
at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression1 node) at System.Linq.Expressions.Expression1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList1 arguments) at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node) at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node) at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node) at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection1 nodes, Func2 elementVisitor) at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node) at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression1 node)
at System.Linq.Expressions.Expression1.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node) at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at DelegateDecompiler.DecompileExpressionVisitor.Decompile(Expression expression) at DelegateDecompiler.DecompiledQueryProvider.CreateQuery[TElement](Expression expression) at DelegateDecompiler.DecompileExtensions.Decompile[T](IQueryable1 self)
at Sipc.BackOffice.Areas.LiquidationManagement.Controllers.LiquidationsController.ClaimsGridRead(Liquidation liquidation, DataSourceRequest request) in e:\Code\Sipc.BackOffice\Sipc.BackOffice\Areas\LiquidationManagement\Controllers\LiquidationsController.cs:line 1133
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.InvokeSynchronousActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 parameters) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass81.b__7(IAsyncResult _)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult1.End() at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag) at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult1.End()
at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass25.<>c__DisplayClass2a.b__20()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass25.b__22(IAsyncResult asyncResult)

Set Computed via Fluent API

I'd like to be able to set the computed attribute via fluent api.

Example:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>().Computed(x => x.MyComputedProperty);
    base.OnModelCreating(modelBuilder);
}

InvalidCastException: Unable to cast object for Enum.GetName()

Hi, great library. I ran into a scenario on 0.18 using Enum.GetName(). Please see the following repro:

[Test]
public void Should_be_able_to_decompile_enum()
{
    var actual = Enumerable.Range(1, 3)
        .Select(x => new Foo { Value = x })
        .AsQueryable()
        .Select(x => x.EnumName)
        .Decompile();

    actual.First().Should().Be("A");
}

public enum FooEnum { A = 1, B = 2, C = 3 }
public class Foo
{
    public int Value { get; set; }

    [Computed]
    public string EnumName
    {
        get
        {
            return Enum.GetName(typeof(FooEnum), this.Value);
        }
    }
}

Result StackTrace:

   at DelegateDecompiler.Processor.Process()
   at DelegateDecompiler.Processor.Process(VariableInfo[] locals, IList`1 args, Instruction instruction, Type returnType)
   at DelegateDecompiler.MethodBodyDecompiler.Decompile()
   at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass1.<Decompile>b__0(MethodInfo m)
   at DelegateDecompiler.Cache`2.GetOrAdd(TKey key, Func`2 func)
   at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method)
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
   at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at DelegateDecompiler.DecompiledQueryProvider.CreateQuery[TElement](Expression expression)
   at DelegateDecompiler.DecompileExtensions.Decompile[T](IQueryable`1 self)
Result Message: System.InvalidCastException : Unable to cast object of type 'System.RuntimeType' to type 'System.Reflection.FieldInfo'.

Operators `as` and `is` are not supported

class Parent {}
class Child : Parent {}

[Test]
public void TypeAsTest()
{
    Expression<Func<Parent, Child>> expected = parent => parent as Child;
    Func<Parent, Child> compiled = parent => parent as Child;
    Test(expected, compiled);
//  Expected: "(parent As Child)"
//  But was:  "Convert(parent)"
}

[Test]
public void TypeIsTest()
{
    Expression<Func<Parent, bool>> expected = parent => parent is Child;
    Func<Parent, bool> compiled = parent => parent is Child;
    Test(expected, compiled);       
// System.InvalidOperationException : The binary operator GreaterThan is not defined for the types 'DelegateDecompiler.Tests.ConvertTests+Parent' and 'DelegateDecompiler.Tests.ConvertTests+Parent'.
}

Updated EFTests to check Nullable and had a problem

Hi @hazzik and @somedave,

Firstly, thanks @hazzik for merging the EF tests into the code.

I synced my repro to get the changes done by @somedave and then added some tests on Nullable. Unfortunately some of them fail with the error message:

LINQ to Entities does not recognize the method 'Int32 GetValueOrDefault()' method, and this method cannot be translated into a store expression.

Please check that my tests make sense. Let me know if I have got anything wrong.

Compute - Include - Decompile problem

Look at this test:

    [Test]
    public void ComputeIncludeDecompileNotFail()
    {
        using (var db = new EfTestDbContext())
        {
            db.EfParents.Where(p => ComputedSample()).Include(p => p.Children).Decompile().Load();
        }
    }

    [Computed]
    private static bool ComputedSample() { return true; }

What happens here? Include returns IQueryable with expression like value(ObjectQuery<...>).Include("Children"). Call of function ComputedSample() is hidden in constant expression and ignored by DelegateDecompiler. => EF fails to execute query.


Что тут происходит? Вызов Includeвозвращает IQueryable с выражением вроде value(ObjectQuery<...>).Include("Children"). Здесь вызов функции ComputedSample() скрыт в константном выражении - а потому игнорируется библиотекой DelegateDecompiler. Как следствие - EF не может выполнить запрос.

Offer of help on documentation/example code

Hi @hazzik,

I have been trying your DelegateDecompiler and it is really nice. I plan to use it to my GenericServices project as it makes the developer experience better.

I have written some unit tests and I'm trying to understand what you support/don't support. I would be happy to write some wiki pages/example code if that helps, but obviously I would need your input. If you are interested in collaborating then let me know.

PS. You will see that I'm pretty keen on good docs. I even build a whole example web site to go with GenericService library.

DelegateDecompiler.EntityFramework with Odata v4

Hi I have a project where I use EF and I have some computed properties. It works fine until I use Odata $top or $skip query options.

{
  "error":{
    "code":"","message":"An error has occurred.","innererror":{
      "message":"Object of type 'DelegateDecompiler.DecompiledQueryable' cannot be converted to type 'System.Linq.IQueryable`1[Entity]'.","type":"System.ArgumentException","stacktrace":"   at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)\r\n   at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)\r\n   at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n   at System.Web.OData.Query.Expressions.SelectExpandBinder.Bind(IQueryable queryable)\r\n   at System.Web.OData.Query.ODataQueryOptions.ApplyTo(IQueryable query, ODataQuerySettings querySettings)\r\n   at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)\r\n   at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
    }
  }
}

i'll appreciate any help.
Thank you.

Decimal multiplication with an int wont work with Nhibernate

Hi,

When multiplying a decimal with an int, NHibernate crashes with "Code supposed to be unreachable" (in StackSpiller.cs inside System.Core) when compiling to a lambda.

The difference between directly executing the code and decompiling it is as follows:
direct
myClass.MyItems.Sum(item=> (item.MyDecimal* Convert(item.MyInt)))

decompiled
myClass.MyItems.Sum(item=> (item.MyDecimal* op_Implicit(item.MyInt)))

I can do a workaround by explicitly put Convert.ToDecimal in my code, but i would like to understand why it goes wrong.

Is this a bug in DelegateDecompiler or in Nhibernate?

(kinda hard to create a testcase because Nhibernate is also needed)

There was another bug but that was fixed by checking out your latest version from the repo. Same error as above, but it was caused by using op_addition instead of + with decimals. (Don't know if it is related, but i thought it was worth mentioning) DelegateDecompiler previously was doing op_addition(decimal1, decimal2) and is now doing decimal1 + decimal2.

Looks like it's because decimal isn't a primitive type.

Nullable decimal arithmetic fails in EF

Failing test in #48. Get an exception for a computed nullable decimal property, "LINQ to Entities does not recognize the method 'System.Decimal GetValueOrDefault()' method, and this method cannot be translated into a store expression."

A simple "and" decompiles to complex "IIF" expression

Hello, I have an entity class with the following method:

public int From;
public int To;
[Computed]
public bool IsBetween(int p) {
   return From <= p && p < To;
}

I would expect it to decompile into a simple binary expression, however, it decompiles into an IIF expression, something like this:

Iif((From > p), false, (p >= To) == false)

I understand that semantically it's of course equivalent, but a where clause with this decompiled expression makes my ORM's query engine fail. Is it possible somehow to force a simple binary expression in this case?

Problems with casting under certain conditions

It appears as though inline casts are getting eaten, but only under certain conditions. I started out noticing this for enums. For example, consider the following test:

[Fact]
public void TestEnumCast()
{
    Expression<Func<TestEnum, bool>> expected = x => (int)x == 10;
    Func<TestEnum, bool> compiled = x => (int)x == 10;
    Test(expected, compiled);
}

This works fine. However, this test does not:

[Fact]
public void TestEnumCast()
{
    Expression<Func<TestEnum, int>> expected = x => (int)x % 10;
    Func<TestEnum, int> compiled = x => (int)x % 10;
    Test(expected, compiled);
}

It fails with System.InvalidOperationException : The binary operator Modulo is not defined for the types 'DelegateDecompiler.Tests.EnumTests+TestEnum' and 'System.Int32'.

This also doesn't work:

[Fact]
public void TestEnumCast()
{
    Expression<Func<TestEnum, bool>> expected = x => new int[]{ (int)x }[0] == 10;
    Func<TestEnum, bool> compiled = x => new int[]{ (int)x }[0] == 10;
    Test(expected, compiled);
}

The error this time is System.InvalidOperationException : An expression of type 'DelegateDecompiler.Tests.EnumTests+TestEnum' cannot be used to initialize an array of type 'System.Int32'

I figured out this wasn't just an enum problem because this test also fails:

[Fact]
public void TestEnumCast()
{
    Expression<Func<int, bool>> expected = x => new short[]{ (short)x }[0] == (short)10;
    Func<int, bool> compiled = x => new short[]{ (short)x }[0] == (short)10;
    Test(expected, compiled);
}

System.InvalidOperationException : The binary operator Equal is not defined for the types 'System.Int16' and 'System.Int32'.

When stepping through the Processor.Process() method, it doesn't appear as though any IL was generated for the casts in these cases. I assume the issue either lies with Mono.Reflection or with the .NET method MethodBase.GetMethodBody() which Mono.Reflection uses. Unfortunately that makes it difficult to figure out how to fix. And since the exceptions are being thrown in the Processor during decompilation, it's not like the expression tree can be walked to add the casts back in (because there is no expression tree yet).

Conditional expression decompiles to IfThenElse instead of Iif

Hello again, probably your fix for my previous issue has introduces a new misbehaviour. I have a property with a simple conditional expression like "a == 1 ? b : c". After decompilation it turns to an If-Else expression instead of a simple Conditional expression type. This again breaks the underlying Linq provider.

Thanks in advance for checking it.

Zoltán

System.ArgumentException : Argument types do not match

I don't know if this code is supposed to run but here goes.

System.ArgumentException : Argument types do not match
   at System.Linq.Expressions.Expression.Constant(Object value, Type type)
   at DelegateDecompiler.Address.Merge(Expression test, Address address1, Address address2, IDictionary`2 map) in Address.cs: line 49
   at DelegateDecompiler.Processor.ProcessorState.Merge(Expression test, ProcessorState leftState, ProcessorState rightState) in Processor.cs: line 63
   at DelegateDecompiler.Processor.<>c__DisplayClass13_0.<ConditionalBranch>b__0() in Processor.cs: line 814
   at DelegateDecompiler.Processor.Process() in Processor.cs: line 122
   at DelegateDecompiler.Processor.Process(VariableInfo[] locals, IList`1 args, Instruction instruction, Type returnType) in Processor.cs: line 97
   at DelegateDecompiler.MethodBodyDecompiler.Decompile() in MethodBodyDecompiler.cs: line 41
   at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass2_0.<Decompile>b__0(MethodInfo m) in DecompileExtensions.cs: line 19
   at DelegateDecompiler.Cache`2.GetOrAdd(TKey key, Func`2 func) in Cache.cs: line 22
   at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method) in DecompileExtensions.cs: line 19
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments) in DecompileExpressionVisitor.cs: line 60
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node) in DecompileExpressionVisitor.cs: line 25
   at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitLambda(Expression`1 node)
   at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node) in DecompileExpressionVisitor.cs: line 50
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(Expression expression) in DecompileExpressionVisitor.cs: line 14
   at DelegateDecompiler.DecompiledQueryProvider.CreateQuery(Expression expression) in DecompiledQueryProvider.cs: line 23
   at DelegateDecompiler.DecompileExtensions.Decompile(IQueryable`1 self) in DecompileExtensions.cs: line 25
   at DelegateDecompiler.Tests.EnumTests.TestComplexProperty() in EnumTests.cs: line 61
IL_0000: nop
IL_0001: ldarg.0
IL_0002: call Int32 get_Id()
IL_0007: ldc.i4.3
IL_0008: cgt
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: brfalse.s IL_0013
IL_0013: ldarg.0
IL_0014: call Int32 get_Id()
IL_0019: ldc.i4.3
IL_001a: cgt
IL_001c: ldc.i4.0
IL_001d: ceq
IL_001f: stloc.2
IL_0020: ldloc.2
IL_0021: brfalse.s IL_0028
IL_0028: ldc.i4.3
IL_0029: stloc.1
IL_002a: br.s IL_002c
IL_0023: nop
IL_0024: ldc.i4.2
IL_0025: stloc.1
IL_0026: br.s IL_002c
IL_000e: nop
IL_000f: ldc.i4.1
IL_0010: stloc.1
IL_0011: br.s IL_002c

The test i ran:

        public class ComplexType
        {
            [Key]
            public int Id { get; set; }

            [Computed]
            public int ComplexProperty
            {
                get
                {
                    if (this.Id > 3)
                    {
                        return 1;
                    }

                    if (this.Id <= 3)
                    {
                        return 2;
                    }

                    return 3;
                }
            }
        }

        public class TestContext : DbContext
        {
            public DbSet<ComplexType> ComplexTypeDbSets { get; set; }
        }

        [Test]
        public void TestComplexProperty()
        {
            var context = new TestContext();
            context.ComplexTypeDbSets.Where(_ => _.ComplexProperty == 1).Decompile();
        }

Support members of interfaces or abstract classes

Hey guys,

I'm trying to make use of your API in one of our new projects, but I'm struggling to get everything to work. I can make use of it when the entity has a property which isn't an override or comes from an interface.

Could somebody show me an example with an abstract BaseEntity class which implements an interface. This interface must have 1 simple String property. The BaseEntity implements the String property as abstract.

A last class comes into play which inherits from BaseEntity and thus overrides the String property which returns a concat of 2 other properties.

Imho this isn't complicated, but I keep getting errors at runtime saying that Linq doesn't know the property....again to be clear: I don't have this with regular computed properties which aren't coming from an inherit or implement.

Unknown LINQ expression of type 'Default'

First off, thanks again for merging all the PRs and for the awesome fixes you did to support nullables. The new OptimizeExpressionVisitor class is particularly nice - can't imagine what it took to figure out how to reduce those trees. I had also started to take a look at implementing OpCodes.Initobj but gave up when I couldn't find a good way to push an address instead of an expression to the stack.

Anyway, I'm now having a different problem in some of my queries:
System.NotSupportedException: Unknown LINQ expression of type 'Default'.

It turns out that Expression.Default is not implemented by LINQ to Entities (and I suspect other ORM LINQ providers as well). I've implemented a fix by getting the default value and then using Expression.Constant instead. An alternative would be to replace the Expression.Default expressions in the OptimizeExpressionVisitor or in another visitor specific to the DelegateDecompiler.EntityFramework library (though then it would be tied to later versions of EF and still wouldn't work for older EF versions).

The processor doesn't handle ILCode.Ldflda

In Processor.cs around line 132 you have:

            else if (instruction.OpCode == OpCodes.Ldfld)
            {
                var instance = stack.Pop();
                stack.Push(Expression.Field(instance, (FieldInfo) instruction.Operand));
            }

There is another opcode - ldflda - that does something similar, but isnøt handled anywhere. One could modify the above to:

            else if (instruction.OpCode == OpCodes.Ldfld || instruction.OpCode == OpCodes.Ldflda)
            {
                var instance = stack.Pop();
                stack.Push(Expression.Field(instance, (FieldInfo) instruction.Operand));
            }

to handle ldflda, in my quick and dirty testing it seems to have the correct effect.

It would probably also be a good idea to add an else at the end to at least warn about unhandled opcodes.

Nullable null comparison generation is different

Test:

Expression<Func<int?, bool>> expected = (x) => x == null;
Func<int?, bool> compiled = (x) => x == null;
Test(expected, compiled);

Result:

IL_0000: ldarga.s System.Nullable`1[System.Int32] x
IL_0002: call Boolean get_HasValue()
IL_0007: ldc.i4.0
IL_0008: ceq
IL_000a: ret
(x == null)
Not(x.HasValue)
  Expected string length 11 but was 15. Strings differ at index 0.
  Expected: "(x == null)"
  But was:  "Not(x.HasValue)"
  -----------^

At runtime this generates a System.ArgumentException: Argument types do not match. Possibly related to #58 (looks like the same class of problem, but that one is comparing totally different types of objects - if I figure this one out, I'll take a look at that one). Looking into it now.

Full runtime exception call stack below for reference:

System.ArgumentException: Argument types do not match
   at System.Linq.Expressions.Expression.Constant(Object value, Type type)
   at DelegateDecompiler.Address.Merge(Expression test, Address address1, Address address2, IDictionary`2 map)
   at DelegateDecompiler.Processor.ProcessorState.Merge(Expression test, ProcessorState leftState, ProcessorState rightState)
   at DelegateDecompiler.Processor.<>c__DisplayClass1c.<ConditionalBranch>b__1b()
   at DelegateDecompiler.Processor.Process()
   at DelegateDecompiler.Processor.Process(VariableInfo[] locals, IList`1 args, Instruction instruction, Type returnType)
   at DelegateDecompiler.MethodBodyDecompiler.Decompile()
   at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass1.<Decompile>b__0(MethodInfo m)
   at DelegateDecompiler.Cache`2.GetOrAdd(TKey key, Func`2 func)
   at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method)
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
   at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
   at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
   at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at DelegateDecompiler.DecompiledQueryProvider.CreateQuery[TElement](Expression expression)
   at DelegateDecompiler.DecompileExtensions.Decompile[T](IQueryable`1 self)

Complex expressions cause error during Merge Method in Address class

Hi,

It seems this row throws an exception when we use Knockout.Mvc package and new version of Delegate decompiler in our application. (v17 cause error but with previous version everything works smoothly)

We want to generate ViewModel included calculated fields with Knockout.MVC and at least one of our expressions looks somethinkg like the following:

  1. address1.Expression will be null (in init phase)
  2. address2.Type is a Value Type

Therefore we get an exception in Address class in Merge method:

 var left = address1.Expression ?? Expression.Constant(null, address2.Type);

To resolve this I suggest to extend the Address class with a "Default" method (almost the same method defined in Process class) and use the Default(...); instead of Expression.Constant(....) everywhere:

static Expression Default(Type type)    {
    //TODO QUESTION: What about Enums?
    //TODO QUESTION: Is this really necessary?
    if (type == null)
        return Expression.Constant(null, typeof(Nullable<>)); 
    if (type.IsValueType)
    {
        // LINQ to entities and possibly other providers don't support Expression.Default, so this gets the default value and then uses an Expression.Constant instead
        return Expression.Constant(Activator.CreateInstance(type), type);
    }
    return Expression.Constant(null, type);

}

Roslyn Test Failures in VS 2015 RTM

I was trying to reproduce a bug I was having only when building/running under VS 2015 RTM so I opened DelegateDecompiler to create a test and discovered a bunch of the existing tests also don't work in VS 2015. I'll assume these are due to Roslyn IL differences. See the screen shot below. I'm going to start trying to knock them out, but some of these may stretch the limits of my IL abilities.

2015-07-23_10h37_57

Unit Tests that test methods with Decompile fail while trying to calculate code coverage

Hello, i have encountered an issue with DelegateDecompiler:
When i try to test methods that use Decompile(), those tests are passing when i just run them, but when i try to calculate code coverage i receive following error in every test that use Decompile():

System.AggregateException: One or more errors occurred. ---> System.InvalidCastException: Specified cast is not valid.
at DelegateDecompiler.Processor.Process(Instruction instruction, Instruction last)
at DelegateDecompiler.Processor.Process(Instruction instruction, Type returnType)
at DelegateDecompiler.MethodBodyDecompiler.Decompile()
at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass1.b__0(MethodInfo m)
at DelegateDecompiler.Cache2.GetOrAdd(TKey key, Func2 func)
at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method)
at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList1 arguments) at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node) at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node) at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node) at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection1 nodes, Func2 elementVisitor) at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node) at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression1 node)
at System.Linq.Expressions.Expression1.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node) at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at System.Linq.Expressions.ExpressionVisitor.VisitArguments(IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) at DelegateDecompiler.DecompileExpressionVisitor.VisitMethodCall(MethodCallExpression node) at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor) at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node) at DelegateDecompiler.DecompileExtensions.Decompile[T](IQueryable1 self)
at IBCM.Models.Readers.TaskReader.d__6.MoveNext() in D:\dev\ibcm\src\Models\Readers\TaskReader.cs:line 41
--- End of stack trace from previous location where exception was thrown ---

I tried using nCrunch, dotCover and Visual Studio Coverage Analyzer, but tests are failing no matter which test engine i am using. As i said it happens only when i try to calculate code coverage, tests are working when i run them manually. Example of method with Decompile:

public async virtual Task<Tuple<IEnumerable<TodoInfo>, IEnumerable<MeetingInfo>>> GetPastTasksByContactId(Guid contactId)
        {
            var todoes = await taskService.GetPastTodoesByContactId(contactId).Project().To<TodoInfo>().Decompile().ToListAsync();
            var meetings = await appointmentService.GetPastMeetingsByContactId(contactId).Project().To<MeetingInfo>().Decompile().ToListAsync();

            return new Tuple<IEnumerable<TodoInfo>, IEnumerable<MeetingInfo>>(todoes, meetings);
        }

Endless loop in GetJoinPoint

When calculating a value in a foreach loop, delegatedecompiler will get stuck in GetJoinPoint.
Doing a sum on TotalPrice in TestContainer will fail (keeps on going endlessly)

Please see the testcase: http://hastebin.com/tabijojoku.csharp

  public class TestContainer
        {
            public List<TestItem> Items { get; set; }

            [Computed]
            public decimal TotalPrice
            {
              //  get { return this.Items.Sum(s => s.TotalPrice); } //This works

                //This causes GetJoinPoint to go in an endless loop
                get
                {
                    decimal total = 0;
                    foreach (var item in this.Items)
                    {
                        total += item.TotalPrice;
                    }
                    return total;
                }
            }
        }

        public class TestItem
        {
            public int Amount { get; set; }
            public decimal Price { get; set; }

            [Computed]
            public decimal TotalPrice
            {
                get { return this.Amount*this.Price; }
            }
        }

Problem with Any() test

I'm doing some tests to understand what DelegateDecompiler supports so I can write some documentation. I ran across a problem which I need to understand why it didn't work.

My computed property was
[Computed] public bool AnyTest { get { return Name.Any( x => x == 'B'); }}

and the test was:
var list = db.ProductCategories.Select(c => c.AnyTest).Decompile().ToList();

I got the error
System.InvalidOperationException : The binary operator Equal is not defined for the types 'System.Char' and 'System.Int32'.

Is .Any() supported in this way (I see it in the tests) or any I doing something wrong?

Can't get auto Decompile via configuration to work

I'm trying to get the auto decompile to work as shown here: http://daveaglick.com/posts/computed-properties-and-entity-framework
But it doesn't work :(

Not sure what I'm doing wrong.

Here's the class that has a computed value.

public class Person
{
    public int Id { get; set; }
    public string First { get; set; }
    public string Last { get; set; }

    [NotMapped]
    [Computed]
    public string Full { get { return First + " " + Last; } }
}

This is the configuration.

public class DelegateDecompilerConfiguration : DefaultConfiguration
{
    public override bool ShouldDecompile(MemberInfo memberInfo)
    {
        // Automatically decompile all NotMapped members
        return base.ShouldDecompile(memberInfo) || memberInfo.GetCustomAttributes(typeof(NotMappedAttribute), true).Length > 0;
    }
}

I also tried removing the [NotMapped] and then changed typeof(NotMappedAttribute) to typeof(ComputedAttribute) in the above configuration.

Then I register it like so

DelegateDecompiler.Configuration.Configure(new DelegateDecompilerConfiguration());

In Startup.cs. I also tried putting it directly into my action.

public ActionResult Test()
{
    DelegateDecompiler.Configuration.Configure(new DelegateDecompilerConfiguration());

    var ctx = new ApplicationDbContext();
    var result = ctx.People.Where(x => x.Full.Contains("foo bar")).ToList();

    return View();
}

Neither work :(

If I put .Decompile() on the query then it works as expected. So the DelegateDecompiler is working, but not the configuration.

Does not support Async operations with EF 6.1.1

I use async EF commands and I have found that DelegateDecompiler fails if an Async end command is used, i.e. .ToListAsync(). I think this a new thing in EF version 6.1.1.

The error message is:

System.InvalidOperationException : The source IQueryable doesn't implement IDbAsyncEnumerable<System.Boolean>. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

You can find a test in the new DelegateDecompiler EF Test harness here. It fails on line 31.

(Note: link updated as I have moved the files around)

Decompilation throws exception on a more complex method

Hello, I'm trying to use DelegateDecompiler in more complex scenarios. I'm trying to decompile a method which itself contains lambda expressions and so.

One of my required methods throw an exception on decompile.

In the near past I've succesfully used your library in similar methods (I mean taking one variable parameter and returning a boolean based on some calculation), but surely this kind is a bit more advanced.

Could you please check the following sample project? It would be great to fix it.

http://ww.vertesz.hu/zoli/FailedComplexDecompile.zip

Regards,
Zoltan

Problems with Nullables (Especially In Entity Framework)

I'm having lots of issues with nullable types while using Entity Framework. When I have a [Computed] property that either returns or indirectly uses a nullable and try to use it in a projection, it usually throws a "NotSupportedException: Only parameterless constructors and initializers are supported in LINQ to Entities." The exact same code copied verbatim to the projection instead of through decompilation works fine.

I've also been able to replicate what I think is the same problem by adding the following test case:

[Fact]
public void ExpressionWithNullable()
{
    Expression<Func<int, int?>> expected = x => (int?)x;
    Func<int, int?> compiled = x => (int?)x;
    Test(expected, compiled);
}

It fails with the following output:

Exception Message:
Assert.Equal() Failure
Position: First difference is at position 5
Expected: x => Convert(x)
Actual:   x => new Nullable`1(x)
Stacktrace:
 at DelegateDecompiler.Tests.DecompilerTestsBase.Test[T](Expression`1 expected, T compiled) in e:\Code\DelegateDecompiler\src\DelegateDecompiler.Tests\DecompilerTestsBase.cs:line 22
 at DelegateDecompiler.Tests.NullTests.ExpressionWithNullable() in e:\Code\DelegateDecompiler\src\DelegateDecompiler.Tests\NullTests.cs:line 30
Output:
IL_0000: ldarg.0
IL_0001: newobj Void .ctor(Int32)
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret

I'll try to address this, but my expression tree knowledge is limited. Any tips? Does an immediate fix come to mind?

Support CoreCLR

I spiked this out, the biggest issue will be getting the Mono.Reflection dependency. You'd either need to switch to the MS packages or get that package updated.

NotSupportedException thrown when running a EF query with Decompile()

Hi,

I have a EF entity that looks like this:

public class Order
{
        public int Id { get; set; }
        public DateTime DateCreated { get; set; }
        public string ClerkNumber {get; set; }
        public decimal Price { get; set; }
        public decimal TaxRate {get; set; }

        [Computed]
        public decimal FinalPrice
        {
            get { return Price*(1 + (TaxRate/100)); }
        }
}

And when I try to make this query using Decompile():

_context
    .Order
    .Where(o => o.ClerkNumber == clerkNumber)
    .OrderByDescending(o => o.DateCreated)
    .Take(100)
    .Select(o => new OrderHistoryModel
    {
        ID = o.ID,
        DateCreated = o.DateCreated,
        FinalPrice = o.FinalPrice
    })
    .Decompile()
    .ToList();

It throws an NotSupportedException saying "Unknown LINQ expression of type 'Increment'."
Here is the full stack trace:

System.NotSupportedException
    Unknown LINQ expression of type 'Increment'.
    at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
    at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitBinary(BinaryExpression b)
    at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
    at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitUnary(UnaryExpression u)
    at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
    at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitMemberAssignment(MemberAssignment assignment)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitBinding(MemberBinding binding)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitBindingList(ReadOnlyCollection`1 original)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitMemberInit(MemberInitExpression init)
    at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
    at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitLambda(LambdaExpression lambda)
    at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
    at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitUnary(UnaryExpression u)
    at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
    at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original)
    at System.Linq.Expressions.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression m)
    at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
    at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.Nominate(Expression expression, Func`2 localCriterion)
    at System.Data.Entity.Core.Objects.ELinq.Funcletizer.Funcletize(Expression expression, Func`1& recompileRequired)
    at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter..ctor(Funcletizer funcletizer, Expression expression)
    at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.CreateExpressionConverter()
    at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
    at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
    at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
    at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
    at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
    at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
    at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
    at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
    at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
    at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)

The package versions that I'm using is:

<package id="DelegateDecompiler" version="0.11.1.0" targetFramework="net451" />
<package id="EntityFramework" version="6.1.1" targetFramework="net451" />

Thanks!

ArgumentException - Argument type mismatch when using Double.ToString("0.##") in a decompilable expression

In the previous versions I had no problem decompiling this property:

public string PackageInfo {
  get { return Quantity.ToString("0.##") + " " + Unit; }
}

In the latest version it throws an ArgumentException with the following stack strace.

System.ArgumentException: Az argumentumtípusok nem egyeznek
   at System.Linq.Expressions.Expression.Constant(Object value, Type type)
   at DelegateDecompiler.Address.Merge(Expression test, Address address1, Address address2, IDictionary`2 map)
   at DelegateDecompiler.Processor.ProcessorState.Merge(Expression test, ProcessorState leftState, ProcessorState rightState)
   at DelegateDecompiler.Processor.<>c__DisplayClass1c.<ConditionalBranch>b__1b()
   at DelegateDecompiler.Processor.Process()
   at DelegateDecompiler.Processor.Process(VariableInfo[] locals, IList`1 args, Instruction instruction, Type returnType)
   at DelegateDecompiler.MethodBodyDecompiler.Decompile()
   at DelegateDecompiler.DecompileExtensions.<>c__DisplayClass1.<Decompile>b__0(MethodInfo m)
   at DelegateDecompiler.Cache`2.GetOrAdd(TKey key, Func`2 func)
   at DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method)
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments)
   at DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at DelegateDecompiler.DecompileExpressionVisitor.Decompile(Expression expression)

Thank you,
Zoltán

Problem updating DelegateDecompiler.EntityFramework

My local NuGet library, GenericServices, has a Nuget .nuspec file that currently references 0.13.0 version of . Now that 0.14.0 is out I wanted to update my application to that, which I do with the command Update-Package DelegateDecompiler.EntityFramework. However I get the error when I do that. The PM command and the resultant error is given below.

PM> Update-Package DelegateDecompiler.EntityFramework
Updating 'DelegateDecompiler.EntityFramework' from version '0.13.0.0' to '0.14.0' in project 'SampleMvcWebAppComplex'.
Update-Package : Unable to resolve dependency 'DelegateDecompiler (= 1.0.0.0)'.
At line:1 char:1
+ Update-Package DelegateDecompiler.EntityFramework
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Update-Package], Exception
    + FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.UpdatePackageCommand

Casting to decimal fails

When casting a number to a decimal, the following error is given:
"Expression of type 'System.Int32' cannot be used for constructor parameter of type 'System.Boolean'"

A work around is by doing

new Decimal(number)

Please see testcase here:
http://hastebin.com/tiridajefo.cs

Coercion error when trying to decompile a bool property

As an example, if I try to decompile this property:

[Computed]
public bool HasExpirationDate { get { return true; } }

I get the following error:

No coercion operator is defined between types 'System.Int32' and 'System.Boolean'.

And here is the stack trace:

[InvalidOperationException: No coercion operator is defined between types 'System.Int32' and 'System.Boolean'.]
System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method) +6156301
DelegateDecompiler.MethodBodyDecompiler.Decompile() +472
DelegateDecompiler.<>c__DisplayClass1.b__0(MethodInfo m) +95
DelegateDecompiler.Cache2.GetOrAdd(TKey key, Func2 func) +420
DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method) +219
DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList`1 arguments) +88
DelegateDecompiler.DecompileExpressionVisitor.VisitMember(MemberExpression node) +339
DelegateDecompiler.DecompileExpressionVisitor.Decompile(Expression expression) +92

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.