2014-11-06 58 views
0

該物業目前已經困擾我好幾天了....創建表達式樹分配到列表

如果我有我自己的對象的列表SearchResults和SearchResult所包含對象的多個列表,所有這些都匹配(布爾)屬性,我怎樣才能重新表達式樹來實現以下目標:

//searchResults is a List<SearchResults> 

searchResults[i].Comments = searchResults[i].Comments.Select(p1 => 
{ 
    p1.Match = ListOfStringVariable.All(p2 => 
    { 
     string value = (string)typeof(CommentData).GetProperty(propertyName).GetValue(p1); 
     return value.Contains(p2); 
    }); 
    return p1; 
}).OrderByDescending(x => x.Match); 

.... 

public class SearchResults 
{ 
    public IEnumerable<CommentData> Comments { get; set; } 
    public IEnumerable<AdvisorData> Advisors { get; set; } 
} 

public class CommentData 
{ 
    public string CommentText { get; set; } 
    public bool Match { get; set; } 
} 

public class AdvisorData 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public bool Match { get; set; } 
} 

,因爲我不知道在編譯時需要被賦予的屬性所需要的表達式樹,無論是它是評論,顧問等(因爲這是一個更大問題的簡化)。上面的例子僅用於評論,那麼如何在沒有條件塊的情況下使用相同的代碼來分配給顧問?

非常感謝

更新:

到目前爲止,使用反射,我們有以下的StriplingWarrior

var searchResult = searchResults[i]; 
foreach (var srProperty in searchResultsProperties) 
{ 
    var collectionType = srProperty.PropertyType; 
    if(!collectionType.IsGenericType || collectionType.GetGenericTypeDefinition() != typeof(IEnumerable<>)) 
    { 
     throw new InvalidOperationException("All SearchResults properties should be IEnumerable<Something>"); 
    } 
    var itemType = collectionType.GetGenericArguments()[0]; 
    var itemProperties = itemType.GetProperties().Where(p => p.Name != "Match"); 
    var items = ((IEnumerable<IHaveMatchProperty>) srProperty.GetValue(searchResult)) 
     // Materialize the enumerable, in case it's backed by something that 
     // would re-create objects each time it's iterated over. 
     .ToList(); 
    foreach (var item in items) 
    { 
     var propertyValues = itemProperties.Select(p => (string)p.GetValue(item)); 
     item.Match = propertyValues.Any(v => searchTerms.Any(v.Contains)); 
    } 
    var orderedItems = items.OrderBy(i => i.Match); 
    srProperty.SetValue(srProperty, orderedItems); 
} 

然而orderedItemsSystem.Linq.OrderedEnumerable<IHaveMatchProperty,bool>型的,需要轉換爲IEnumerable<AdvisorData>。下面將引發錯誤:

'System.Linq.Enumerable.CastIterator(System.Collections.IEnumerable)' 是 '方法',但使用像 '類型'

var castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(new[] {propertyType}); 
var result = castMethod.Invoke(null, new[] { orderedItems }); 

其中propertyType是類型AdvisorData

+0

1.你真的不應該在'Select()'lambda中設置屬性。 2.你肯定需要表達樹嗎?如果你使用的是LINQ到對象,你應該能夠通過一些基本的反思來獲得。 3.您可以考慮使用另一個類,例如'SearchResults ',它具有'Match'屬性,而不是將匹配屬性放在結果上。如果你是肯定的,你需要CommentData等有一個Match屬性,如果你讓它們在它上面實現一個與該屬性的接口,你可能會讓它更容易。 – StriplingWarrior 2014-11-06 19:17:46

+0

@StriplingWarrior選擇中的分配以便我不必完全重新創建新列表。我如何使用反射來創建上述?它似乎超出了僅僅反思的範圍。另外,我也提到了MatchData接口和Match屬性,但現在已經刪除了它,因爲它簡化了我的開發過程並且很容易重新引入。非常感謝 – tic 2014-11-06 19:36:57

+0

我知道你爲什麼選擇將作業放在那裏。這仍然是不好的做法。如果您要將註釋視爲集合並對其進行修改,請使用'for'循環。無論如何,上面的代碼已經使用反射來獲取CommentData上的屬性值。迭代所有SearchResults的值也不應該太大。你需要哪些幫助? (儘量保持您的問題儘可能具體。) – StriplingWarrior 2014-11-06 20:13:53

回答

1

首先,讓你的類型實現這個接口,這樣你就不必做這麼多的反思:

public interface IHaveMatchProperty 
{ 
    bool Match { get; set; } 
} 

然後寫代碼,做像這樣的東西。 (我做了很多假設,因爲你的問題並不是非常清楚你想要的行爲是什麼。)

var searchResult = searchResults[i]; 
foreach (var srProperty in searchResultsProperties) 
{ 
    var collectionType = srProperty.PropertyType; 
    if(!collectionType.IsGenericType || collectionType.GetGenericTypeDefinition() != typeof(IEnumerable<>)) 
    { 
     throw new InvalidOperationException("All SearchResults properties should be IEnumerable<Something>"); 
    } 
    var itemType = collectionType.GetGenericArguments()[0]; 
    var itemProperties = itemType.GetProperties().Where(p => p.Name != "Match"); 
    var items = ((IEnumerable<IHaveMatchProperty>) srProperty.GetValue(searchResult)) 
     // Materialize the enumerable, in case it's backed by something that 
     // would re-create objects each time it's iterated over. 
     .ToList(); 
    foreach (var item in items) 
    { 
     var propertyValues = itemProperties.Select(p => (string)p.GetValue(item)); 
     item.Match = propertyValues.Any(v => searchTerms.Any(v.Contains)); 
    } 
    var orderedItems = items.OrderBy(i => i.Match); 
    srProperty.SetValue(srProperty, orderedItems); 
} 
+0

感謝您的幫助orderedItems是OrderedEnumerable 但需要IEnumerable (作爲示例)什麼是最好的投射方式? – tic 2014-11-07 18:43:52

+0

@tic:您可能需要使用反射創建一個調用'Enumerable.Cast <>()'。 – StriplingWarrior 2014-11-07 21:23:17

+0

我的演員不能工作,我已經把它放在更新中。 – tic 2014-11-11 17:48:17