Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a lambda expression with a new anonymous type at runtime

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.

like image 545
EPLKleijntjens Avatar asked May 30 '13 13:05

EPLKleijntjens


People also ask

Is lambda expression An anonymous function?

Note that a lambda expression looks a lot like a method declaration; you can consider lambda expressions as anonymous methods—methods without a name.

Is lambda expression An anonymous class?

A lambda expression is a short form for writing an anonymous class. By using a lambda expression, we can declare methods without any name.

When can anonymous types be created C#?

In C#, you are allowed to create an anonymous type object with a new keyword without its class definition and var is used to hold the reference of the anonymous types. As shown in the below example, anony_object is an anonymous type object which contains three properties that are s_id, s_name, language.

What is the difference between an anonymous type and a regular data type?

From the perspective of the common language runtime, an anonymous type is no different from any other reference type, except that it cannot be cast to any type except for object.


1 Answers

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 Reflectoin.Emit.

like image 131
sircodesalot Avatar answered Sep 20 '22 19:09

sircodesalot