Erstellen Sie zur Laufzeit einen Lambda-Ausdruck mit einem neuen anonymen Typ

anonymous-types c# entity-framework expression-trees reflection

Frage

Ich möchte eine Methode aufrufen, die einen Parameter wie folgt erwartet:

Expression<Func<sometype, 'a>> expr

Ich muss diesen Parameter zur Laufzeit konstruieren, weil ich nicht weiß, wie der anonyme Typ vorher aussehen wird; Es könnte beliebig viele Felder enthalten:

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

Ich kann einen Typ zur Laufzeit erstellen, der die gleiche "Signatur" (Ist das das richtige Wort dafür?) Als den gewünschten anonymen Typ hat, aber die Frage ist: Wie konstruiere ich diesen Lambda-Ausdruck zur Laufzeit daraus? Vor allem Expression.New stört mich, weil ich eine constructorInfo übergeben muss, die ich von einem existierenden Typ bekommen muss (der zwar ein anonymer Typ sein kann, aber ich kann zur Laufzeit keinen anonymen Typ erstellen. Oder ist es da? eine Möglichkeit, das zu tun?).

Update (ein Kontext wie in den Kommentaren gefordert)

Die Methode, die ich aufrufen möchte, ist:

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

Der Grund dafür ist, dass eine Navigationseigenschaft für eine Entität, die von einer bestimmten Basisklasse erbt, automatisch den Schlüssel dieser Basisklasse im Fremdschlüssel enthält. Da eine Entität mehrere Schlüsselfelder eines beliebigen Typs haben kann, ist mir der Typ TKey nur zur Laufzeit bekannt.

Akzeptierte Antwort

Verwenden Sie eine separate Methode:

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;
}

Beachten Sie jedoch, dass der Starttyp (in meinem Beispiel String ) im Voraus bekannt sein muss.

Aktualisierung :

Da es so klingt, als ob Sie einen Typ dynamisch erstellen möchten, gebe ich Ihnen ein einfaches Beispiel dafür.

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();
}

Wie Sie sehen können, ist dies ein wenig komplizierter. Wenn Sie das Thema jedoch weiter studieren möchten, verweisen Sie auf Reflectoin.Emit .


Expertenantwort

Anonyme Typen sind eine Compiler-Funktion. Wenn der Compiler sie nicht zur Kompilierzeit erstellt, müssen Sie eine Meta-Programmierung verwenden - entweder TypeBuilder oder vielleicht CSharpCodeProvider . Sie könnten besser Tupel verwenden - zumindest sind sie einfach zu erstellen (Sie können Tuple.Create einfach genug verwenden).

Wie für den Ausdruck; Ich würde vorschlagen, es als Expression<Func<sometype, object>> - was für jede Formulierung funktioniert. Der Code , der den Expression kann natürlich sehen, was der tatsächliche Typ ist.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum