7

I want to invoke a method that expects a parameter like this:

Expression<Func<sometype, 'a>> expr

I need to construct this parameter at runtime, because I won't know what the anonymous type will look like before; it could have any amount of fields:

x => new { a=x.a, b=x.b, c=x.c, etc... }

I can create a type at runtime that has the same 'signature' (Is that the correct word for this?) as the desired anonymous type, but the question is: How do I construct this lambda expression at runtime from that? Especially Expression.New is bugging me, because I need to pass a constructorInfo to it that I have to get from an existing type (which can indeed be an anonymous type, but I can't create an anonymous type at runtime. Or is there a way to do that?).

Update (some context as requested in the comments)

The method I want to invoke is:

DependentNavigationPropertyConfiguration.HasForeignKey<TKey>(Expression<Func<TDependentEntityType, TKey>> foreignKeyExpression)

The reason I want to do this is to automatically make a navigation property to an entity that inherits from a certain base class include the key of that base class in the foreign key. Because an entity can have multiple key fields of any type, the type TKey is only known to me at runtime.

svick
  • 236,525
  • 50
  • 385
  • 514
EPLKleijntjens
  • 916
  • 1
  • 8
  • 21
  • What is the input of you scenario? Do you construct it at run-time from string-base data? – Ilya Ivanov May 30 '13 at 13:59
  • At runtime a number of fields are selected from 'sometype'. I need to build the expression from that. The names of the fields of the anonymous type are the same as the fields that were selected from 'sometype'. – EPLKleijntjens May 30 '13 at 14:03
  • Why the downvote? Please explain so that I might learn someday. – EPLKleijntjens May 30 '13 at 15:20

3 Answers3

16

Use a separate method:

public static void Main()
{
    var myExpression = Express(str => new { 
        String = str, 
        Length = str.Length 
    });

    // We can compile/use it as well...
    var compiledExpression = myExpression.Compile();
    var anonymousOutput = compiledExpression("Input String");

    Console.WriteLine(anonymousOutput.String); // Output: Input String
    Console.WriteLine(anonymousOutput.Length); // Output: 12

    Debug.WriteLine(myExpression); // Output: "str => new <>f__AnonymousType0`2(String = str, Length = str.Length)"
    Console.ReadLine();
}


static Expression<Func<String, T>> Express<T>(Expression<Func<String, T>> expression)
{
    return expression;
}

Note however, that the starting type (in my example String) must be known up front.

Update:

Since what it sounds like you're trying to do is dynamically create a type, I'll give you a simple example of how to do that.

public static void Main()
{
        // Create an anonymous type with two fields
    Type myAnonymousType = CreateNewType<String, Int32>();
    dynamic myAnon = Activator.CreateInstance(myAnonymousType);

    myAnon.FieldA = "A String";
    myAnon.FieldB = 1234;


    Console.WriteLine(myAnon.FieldA); // Output : "AString"
    Console.WriteLine(myAnon.FieldB); // Output : 1234
    Console.ReadLine();
}

public static Type CreateNewType<TFieldTypeA, TFieldTypeB>()
{
    // Let's start by creating a new assembly
    AssemblyName dynamicAssemblyName = new AssemblyName("MyAsm");
    AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("MyAsm");

    // Now let's build a new type
    TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("MyAnon", TypeAttributes.Public);

    // Let's add some fields to the type.
    FieldInfo dynamicFieldA = dynamicAnonymousType.DefineField("FieldA", typeof(TFieldTypeA), FieldAttributes.Public);
    FieldInfo dynamicFieldB = dynamicAnonymousType.DefineField("FieldB", typeof(TFieldTypeB), FieldAttributes.Public);

    // Return the type to the caller
    return dynamicAnonymousType.CreateType();
}

As you can see, this is a little more complicated. If you want to study the topic further though, definitely reference Reflection.Emit.

Kapé
  • 4,411
  • 3
  • 37
  • 54
sircodesalot
  • 11,231
  • 8
  • 50
  • 83
  • 1
    Thanks, that's a nice trick, but unfortunately, it doesn't solve my main problem, namely that I don't know what the anonymous type will look like until runtime (amount of fields is variable). So I can't actually make the expression anywhere. – EPLKleijntjens May 30 '13 at 14:17
  • Oh I see. So, the thing with that is, an anonymous type is a compiler feature, that is, when you write an anonymous, the compiler actually builds it to a specific class with some random name (in my example `<>f__AnonymousType0'2`). So you can't really *easily* create an anonymous type at runtime. You could get away with using `Expression.New`, but that requires a constructor, which implies it needs to be an existing type. You can define a *new* type to get around this, but that's really an altogether separate question. If you want I can write an example. – sircodesalot May 30 '13 at 14:22
  • Thanks again for your trouble. I know how to create the type I need using reflection, but the problem is that, using that type, I can't create an expression that creates a new anonymous type. I added some context to my original question. If I invoke the method mentioned with an expression created from a newly created type through reflection, I get an exception telling me the type of expression doesn't fit, because it expects either a property expression or one with an anonymous type... – EPLKleijntjens May 30 '13 at 14:40
  • I'm having trouble with this part: `I can't create an expression that creates a new anonymous type`. An anonymous type is a compiler feature only available at compile time. You can't create an "anonymous type" at runtime. You can create a new type yourself, but that's not strictly speaking an "anonymous type". – sircodesalot May 30 '13 at 14:46
  • 2
    What I mean is that I can create this expression: **x=>new MyAnonymousType() {a=x.a, b=x.b}**, but I can't create **x=>new {a=x.a, b=x.b}** The method I'm trying to invoke expects the second kind of expression (without explicit type). – EPLKleijntjens May 30 '13 at 15:18
3

Anonymous types are a compiler feature. If you don't get the compiler to create them at compile-time, then you will have to use meta-programming - either TypeBuilder or maybe CSharpCodeProvider. You might be better off using tuples - at least they are easy to create (you can use Tuple.Create easily enough).

As for the expression; I would suggest typing it as Expression<Func<sometype, object>> - which will work for any formulation. The code inspecting the Expression can of course see what the actual type is.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I have anonymous type as parameter expression type and I need to return a typed selector. I've tried to use `Expression>` return type and cast `Expression.Lambda(Expression.Convert(body, typeof(object)), parameterExpression)` to it, but it complains it can't cast type... What do I do? – Alexander Sep 10 '21 at 11:08
  • @Alexander why do you need to do *anything*? if you want to convert to `object`: just do that?` `object x = theDynamicThing;` – Marc Gravell Sep 10 '21 at 14:07
  • Sorry, confused you a bit. It's because I don't create a new type as a topic starter, instead I need to return Lambda: `public static Expression> GetPropertySelector(string propertyName, dynamic type) { var expr = Expression.Parameter(type, "x"); Expression body = expr; foreach (var member in propertyName.Split('.')) body = Expression.Property(body, member); return Expression.Lambda(Expression.Convert(body, typeof(object)), expr); }` and getting now weird `Cannot implicitly convert type ... to 'System.Linq.Expressions.Expression>'` – Alexander Sep 10 '21 at 14:44
  • @Alexander l; I'm not going to try and guess at your setup here; this kind of question really needs to start with a reproducible, runnable example – Marc Gravell Sep 10 '21 at 15:11
  • I've created test example: https://rextester.com/BNW81430 (I know it looks weird where anonymous type variable is created :)) - I am trying to create Extension method which consumes two `GroupJoin`. And the given method supposed to be part of it, constructing selector for the second GroupJoin which has anonymous type part... – Alexander Sep 10 '21 at 17:42
-8

you can do simply like this

context.Students.Join(context.Courses, a => a.Course_id, b => b.Course_id, (a, b) => new { Student= a, Course= b }).Where(x => x.Student_id == studentId)
      .Select(y => new
      {
         StudentId = y.Student.StudentId,
         RegistrationNumber = y.Student.RegNo,
         Name = y.Student.Name,
         Coursename = y.Course.Name
      }).ToList();
Baby Groot
  • 4,637
  • 39
  • 52
  • 71
Shahid Iqbal
  • 375
  • 3
  • 5
  • 2
    How does this answer the question? – svick Jan 07 '14 at 10:12
  • You can get an anonymous type at run time without any need to populate data in a known type. May be not very relevant to question but helpfull – Shahid Iqbal Jan 07 '14 at 10:53
  • 1
    It is important to understand, that `new` statements like in your example are not creating anonymous types at *compile time*. That's why this answer has nothing to do with the question and therefore is not helpful at all. – CodeFox May 04 '18 at 13:31