2014-02-19 41 views
0

我需要一個表達式獲取集合的每個項目的類型。在運行時獲取列表的項目類型在c#

我有這樣一個集合:

var collection = new List<object>{1,2.2,"string",'c'}; 

有可能獲得集合的每一個項目的類型是這樣的:

var myVariable= collection.Select(item => item.GetType()) 

但我需要在運行時創建這個表達。 我必須動態創建類似myVariable的東西,但怎麼做?!

調試器顯示我的myVariable內部表達的價值是這樣的:

{System.Linq.Enumerable+WhereSelectListIterator`2[System.Object,System.Type]} 

EDIT1

的問題說明: 假設我需要選擇一個對象的一個​​屬性。我的貓寫這樣的查詢:

var lst = new List<MyClass> 
     { 
      new MyClass {Name = "myName1", Value = 1}, 
      new MyClass {Name = "myName2", Value = 2} 
     }; 
     var oneProperty = lst.Select(item => new {SelectedProp=item.Name}); 

結果是匿名類型包含2個項目的清單:「myName1」 &「myName2」。 現在我想添加另一個屬性到結果列表,顯示所選屬性的類型。下面的代碼讓我這樣列表:

  var oneProperty = lst.Select(item => new {SelectedProp=item.Name,TypeOfProp=item.GetType() }); 

的問題是建立在運行時這樣表達給予表達實體框架,它執行的表達。問題解決了嗎?

+0

顯示我們的僞代碼你想達到的目標。 – dcastro

+1

鑑於提出的解決方案不能解決您的問題,請澄清您正在努力實現的目標! – Georg

+0

發佈編輯和問題解釋 – Merta

回答

1

鑑於您最近編輯,這裏是如何編譯這樣的表達式在運行時執行以下操作:

item => new AnonymousType() { SelectProp = item.name, TypeOfProp = item.GetType() } 

我添加了註釋,以顯示錶達式是如何被構建。您可以根據自己的需求進行調整。

[Fact] 
public void CreateExpression() 
{ 
    Type argType = typeof (MyClass); 
    string propertyName = "Name"; 

    ParameterExpression paramExpression = Expression.Parameter(argType, "item"); 

    //Create "item.Name" and "item.GetType()" expressions 
    var propertyAccessExpression = Expression.Property(paramExpression, propertyName); 
    var getTypeExpression = Expression.Call(paramExpression, "GetType", Type.EmptyTypes); 

    Type anonType = CreateAnonymousType<String, Type>("SelectedProp", "TypeOfProp"); 

    //"SelectProp = item.name" 
    MemberBinding assignment1 = Expression.Bind(anonType.GetField("SelectedProp"), propertyAccessExpression); 
    //"TypeOfProp = item.GetType()" 
    MemberBinding assignment2 = Expression.Bind(anonType.GetField("TypeOfProp"), getTypeExpression); 

    //"new AnonymousType()" 
    var creationExpression = Expression.New(anonType.GetConstructor(Type.EmptyTypes)); 

    //"new AnonymousType() { SelectProp = item.name, TypeOfProp = item.GetType() }" 
    var initialization = Expression.MemberInit(creationExpression, assignment1, assignment2); 

    //"item => new AnonymousType() { SelectProp = item.name, TypeOfProp = item.GetType() }" 
    Expression expression = Expression.Lambda(initialization, paramExpression); 
} 

你需要這個方法來創建一個新的匿名類型:

public static Type CreateAnonymousType<TFieldA, TFieldB>(string fieldNameA, string fieldNameB) 
{ 
    AssemblyName dynamicAssemblyName = new AssemblyName("TempAssembly"); 
    AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run); 
    ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("TempAssembly"); 

    TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("AnonymousType", TypeAttributes.Public); 

    dynamicAnonymousType.DefineField(fieldNameA, typeof(TFieldA), FieldAttributes.Public); 
    dynamicAnonymousType.DefineField(fieldNameB, typeof(TFieldB), FieldAttributes.Public); 

    return dynamicAnonymousType.CreateType(); 
} 
+0

非常感謝!這正是我需要的!最好的祝福:) – Merta

1

myVariable這樣的對象實現了通用接口IEnumerable<T>。因此,你可以檢索界面,並獲得元素類型的泛型參數:

var type = myVariable.GetType(); 
foreach (var i in type.GetInterfaces()) 
{ 
    if (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)) 
    { 
     return i.GetGenericTypeArguments()[0]; 
    } 
} 
// not a generic collection 
return typeof(object); 

編輯:還是你只需要類型的元素?由於IEnumerable<T>的類型參數是協變的,因此您可以通過將其轉換爲IEnumerable<object>來實現此目的。

collection.Cast<object>().Select(o => o.GetType()) 
+0

謝謝格奧爾格,但我需要動態創建一個表達式!您的答案在運行時不會創建任何表達式。 – Merta

+0

您可以使用從此代碼中檢索到的類型,並使用相應的類型參數調用Select擴展方法 – Georg

+0

我需要創建一個表達式,通過執行它,可以填充myVariable。 – Merta

0

你只需要遍歷列表以獲得實際類型:

var collection = new List<object> { 1, 2.2, "string", 'c' }; 
    var myVariable = collection.Select(item => item.GetType()); 

    foreach(var m in myVariable) 
    { 
     Console.WriteLine(m.FullName); 
    } 

編輯:

你在調試器中看到的類型:

{System.Linq.Enumerable+WhereSelectListIterator`2[System.Object,System.Type]} 

是由myVariable表示的Linq查詢的運行時類型。您需要迭代這樣的查詢才能獲取各個值。 乾杯

+0

:D你想教Console.WriteLine()嗎? – Merta

+0

這只是一個示例,表明在foreach循環中,您將能夠獲得您正在尋找的實際類型。 –

+0

Mrlucmorin謝謝您,您認爲myVariable的值由「選擇」功能提供。但問題是創建一個名爲「表達式」的東西,在運行時獲得「選擇」功能的結果。 – Merta

相關問題