Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anonymous object creation #75

Open
holden888 opened this issue Mar 11, 2018 · 5 comments
Open

Anonymous object creation #75

holden888 opened this issue Mar 11, 2018 · 5 comments
Milestone

Comments

@holden888
Copy link

how to get from:

string strExpression = "x => new { x.Ido, x.OtdName }";

such expression:

Expression<Func<T, object>> result = x => new {x.Ido, x.OtdName };

I need this to select specific fields in Generic Repository:

public async Task<List<object>> GetList1(Expression<Func<T, object>> selectFields)
        {
            IQueryable<T> query = _dbSet;
            IQueryable<object> result;
         
            result = query.Select(selectFields);

            return await result.AsNoTracking().ToListAsync();
        }
@holden888
Copy link
Author

holden888 commented Mar 11, 2018

For the same field works like this:

string strExpression = "x.Ido";
var interpreter = new Interpreter();
Expression<Func<T, object>> expression = interpreter.ParseAsExpression<Func<T, object>>(whereExpression, "x");

How to do this for multiple fields?:

string strExpression = "x.Ido, x.OtdName";

For:

public async Task<List<object>> GetList1(Expression<Func<T, object>> selectFields)
        {
            IQueryable<T> query = _dbSet;
            IQueryable<object> result;
         
            result = query.Select(selectFields);

            return await result.AsNoTracking().ToListAsync();
        }

@davideicardi
Copy link
Member

You are right, unfortunately for now anonymous object are not supported.

I will think about this for a future release...any help is appreciated 😃

@davideicardi davideicardi changed the title Expression and Generic parameters Anonymous object creation May 1, 2018
@davideicardi davideicardi added this to the 2.x milestone May 1, 2018
@metoule
Copy link
Contributor

metoule commented Jun 8, 2021

I had a look, and it seems quite difficult: the anonymous type has to be defined at runtime, and to do that, you need to add a custom dynamic assembly to the current app domain, and then add the new anonymous type to that custom assembly. Also, that custom assembly must be unloaded when it's no longer needed, to avoid memory bloat. Also, the anonymous type must define fields, properties, a default constructor, and possibly a ToString() method, otherwise it might not be understood by Entity Framework.

Creating a dynamic assembly doesn't seem possible with netstandard 2.0, only with netstandard 2.1.

I found a project that does most of it, except that it doesn't unload the dynamic assembly, and it's also not compatible with netstandard.

https://github.com/dotlattice/LatticeUtils/blob/master/LatticeUtils/AnonymousTypeUtils.cs

@davideicardi
Copy link
Member

Thank you @metoule for the interesting analysis! I agree with your conclusion. For now let's keep the issue open.

@holdenmai
Copy link
Contributor

Another possibility, depending on the outcome desired for this, is to return an ExpandoObject. This would allow consuming code to be able to reference it as dynamic, or be passed to other interpreters since there is already some support for

I do have a decent amount of experience in building classes at run time, especially for the simple classes that are created as anonymous types. Looking into how those are actually compiled out

var o = new { Prop1 = int.MaxValue, Prop2 = string.Empty };

ends up getting compiled out to a class as follows

public class <>f__AnonymousType0`2<Prop1, Prop2>
{
   private readonly Prop1<Prop1>i__Field;
   private readonly Prop2 <Prop2>i__Field;

    public <>f__AnonymousType0`2(Prop1 Prop1, Prop2 Prop2)
    {
        <Prop1>i__Field = Prop1;
        <Prop2>i__Field = Prop2;
    }
    
    public int Prop1 { get => <Prop1>i__Field; }
    public string Prop2 { get => <Prop2>i__Field; }

    public override string ToString()
    {
//Technically calls ToString() with a null check, but this shows the string format.
          return $"{{ Prop1: {Prop1}, Prop2: {Prop2} }}"
    }

    //Had to use ILDisassembler to get here.
    public override bool Equals(object o)
    {
        return o is <>f__AnonymousType0`2<Prop1, Prop2> a && EqualityComparer<Prop1>.Default.Equals(a.Prop1, Prop1) && EqualityComparer<Prop2>.Default.Equals(a.;
    }
    public override int GetHashCode()
    {
        //This is pretty ugly.  Having a hard time decompiling from MSIL in my head at the moment.
//Long story short, combines hash codes with the results from EqualityComparer<T>.Default
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants