2

創建一個新的匿名類型Lambda表達式我想調用一個期望的方法的參數是這樣的:在運行時

Expression<Func<sometype, 'a>> expr 

我需要構建在運行時,這個參數,因爲我不知道是什麼匿名類型看起來像以前一樣;它可以有字段的任何金額:

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

我可以在具有相同的「簽名」運行時創建一個類型(是正確的詞來形容?)作爲期望的匿名類型,但問題是:我該如何在運行時構造這個lambda表達式?特別是Expression.New讓我煩惱,因爲我需要將constructorInfo傳遞給它,我必須從現有類型(它確實可以是匿名類型,但我不能在運行時創建匿名類型)一種方法來做到這一點?)。

更新(如意見要求某些情況下)

我想調用的方法是:

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

我想這樣做是自動進行導航屬性的原因從某個基類繼承的實體在外鍵中包含該基類的鍵。因爲一個實體可以有多個任何類型的鍵字段,所以只有在運行時才知道TKey類型。

+0

什麼是你的情況的輸入?你是從運行時基於字符串的數據構造它嗎? –

+0

在運行時,會從'sometype'中選擇一些字段。我需要從中建立表達。匿名類型的字段的名稱與從'sometype'中選擇的字段相同。 – EPLKleijntjens

+0

爲什麼downvote?請解釋一下,以便我有一天能學會。 – EPLKleijntjens

回答

9

使用一個單獨的方法:然而

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

注意的是,起始類型(在我的例子String)必須是已知的前面。

更新

因爲它聽起來就像你試圖做的是動態創建一個類型,我給你如何做一個簡單的例子。

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

正如你所看到的,這有點複雜。如果你想進一步研究這個話題,絕對可以參考Reflectoin.Emit

+1

謝謝,這是一個很好的竅門,但不幸的是,它並沒有解決我的主要問題,即我不知道匿名類型在運行時會是什麼樣子(字段數量是可變的)。所以我實際上無法在任何地方表達這個表情。 – EPLKleijntjens

+0

哦,我明白了。所以,那就是,匿名類型是一個編譯器特性,也就是說,當你編寫一個匿名函數時,編譯器實際上會用一些隨機的名字將它構建到一個特定的類中(在我的例子中是'<> f__AnonymousType0'2') 。所以你不能在運行時很容易地創建一個匿名類型。你可以使用'Expression.New'離開,但這需要一個構造函數,這意味着它需要是一個現有的類型。你可以定義一個* new *類型來解決這個問題,但這確實是一個完全獨立的問題。如果你想我可以寫一個例子。 – sircodesalot

+0

更新後的回覆。 – sircodesalot

3

匿名類型是一個編譯器功能。如果你沒有讓編譯器在編譯時創建它們,那麼你將不得不使用元編程 - TypeBuilder或者CSharpCodeProvider。使用元組可能會更好 - 至少它們很容易創建(您可以輕鬆地使用Tuple.Create)。

至於表達;我建議將其輸入爲Expression<Func<sometype, object>> - 這將適用於任何配方。代碼檢查Expression當然可以看到實際類型是什麼。

-6

,你可以簡單地做這樣的

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(); 
+2

這是如何回答這個問題的? – svick

+0

您可以在運行時獲得匿名類型,而無需使用已知類型填充數據。可能與問題無關,但有幫助 –