2014-09-10 55 views
1

我想爲我的對象和表達式創建一個緩存。用下面的代碼,他運行了所有元素,之後他可以使用詞典中的表達式/對象。而不是這樣做,他再次將成員表達式添加到具有相同對象的字典中。使用membrerepression創建字典作爲密鑰

是否有可能創建一個帶有成員表達式的字典,我在這裏做錯了什麼?

private static readonly IDictionary<MemberExpression, object> Cache = new Dictionary<MemberExpression, object>(); 
private static Func<TClass, TProperty> GetCachedMemberFunction<TClass, TProperty>(
    Expression<Func<TClass, TProperty>> member) 
{ 
    Func<TClass, TProperty> func; 
    var memberExpression = member.Body as MemberExpression; 
    if (Cache.ContainsKey(memberExpression)) 
    { 
     func = (Func<TClass, TProperty>)Cache[memberExpression]; 
    } 
    else 
    { 
     func = member.Compile(); 
     Cache[memberExpression] = func; 
    } 

    return func; 
} 

注意:正如你從代碼中看到的,我想創建一個緩存,所以我只需要一次編譯功能。

+1

我在猜測MemberExpression是一個引用類型,沒有實現所需的IEquatable接口。我認爲CLR會爲你編譯表達式。 – 2014-09-10 12:24:08

+0

[最有效的方式來測試lambda表達式的相等]可能的重複(http://stackoverflow.com/questions/283537/most-efficient-way-to-test-equality-of-lambda-expressions) – Athari 2014-09-10 12:24:43

回答

1

首先,我想說的是緩存表達式是應該非常小心地執行的事情,並且實現起來非常複雜,因爲從評論(this question)已經顯示的示例中。有一個原因爲什麼Equals尚未覆蓋表達式,因爲它們比較複雜。

一些與表達的主要問題,當談到對它們進行比較:

  • 比較表達式大約是昂貴的,因爲編譯它們
  • 當你考慮兩個表達式相等?

例如,

y => y.MyProperty.AnotherProperty 
x => x.MyProperty.AnotherProperty 

以上兩個表達式是否相等?這取決於用例(如果您正在分析代碼,您可能需要考慮變量名稱)。此外,考慮下面的例子:

class BaseClass { int MyProperty { get; } } 
class DerivedClass : BaseClass { } 

現在讓我們說我們有兩個表達式是幾乎相等:

BaseClass x => x.MyProperty; 
DerivedClass x => x.MyProperty; 

如果這些被認爲是平等的嗎?可能不會,但也許在你的情況。咆哮的

既然你正在處理MemberExpression是你很可能在做財產的getter和setter或類似的東西。在這種情況下,將Type結合MemberInfo作爲您的Cache對象的關鍵字可能已足夠。 請注意,這僅適用於所有表達式的形式爲x => x.Property而沒有任何嵌套訪問,強制轉換或其他。 在這種情況下,你能想出這樣的事情:

private struct MemberAccessKey 
{ 
    public readonly Type Type; 
    public readonly MemberInfo Member; 

    public MemberAccessKey(Type t, MemberInfo m) 
    { 
     Type = t; Member = m; 
    } 

    public override bool Equals(object obj) 
    { 
     if (!(obj is MemberAccessKey)) return false; 

     var other = (MemberAccessKey)obj; 
     return other.Type == Type && other.Member == Member; 
    } 

    public override int GetHashCode() 
    { 
     return Type.GetHashCode()^Member.GetHashCode(); 
    } 
} 

然後實例它基於一個MemberExpression:

TypeKey key = new TypeKey(typeof(TClass), memberExpression.Member); 

結論

  1. 不要做它因爲性能原因
  2. 不要這樣做因爲性能的原因因爲它只引入錯誤
  3. 不要這樣做!
  4. 如果您知道您創建的每個表達式的格式爲x => x.MyProperty,那麼您可以將其用作關鍵字。請注意,任何其他表單將崩潰或解析爲重複密鑰。