我在我的專案中使用了LINQ運算式,但在編譯該運算式后,它拋出了以下例外:
我的專案中使用了LINQ運算式。
給定的鍵是不存在在詞典中。, at System.ThrowHelper.ThrowKeyNotFoundException()
在System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at lambda_method(Closure , ScanQueryList /span>)
at System.Linq.Enumerable.<>c__DisplayClass6_0`1.<CombinePredicates>b__0(TSource x)
at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext()
我正在使用Dictionary <double[], List<double>>,顯然double[]是關鍵。我使用的linq運算式使用double[]作為鍵從上述字典中獲取資料。
運算式如下:
.Call (.Call ($p.<my_dictionary_name>).get_Item(. Constant<System.Double[] >(System.Double[])).get_Item(0) > 10D
問題似乎發生在.Constant<System.Double[]>(System.Double[]))中,那么我怎樣才能看到上述接受System.Double[]型別的引數傳遞。有什么方法可以除錯或解決這個問題嗎?
uj5u.com熱心網友回復:
你沒有提供生成運算式的代碼,但使用像下面這樣的代碼:
你沒有提供生成運算式的代碼。
//using static System.Linq.Expressions.Expression
var key = new double[] { 1, 2 };
var dict = new Dictionary<double[], List<double> >() {
{key, new List<double>{1,2}}。
};
var expr = Lambda(
屬性(
Constant(dict),
typeof(Dictionary<double[], List<double>>).GetProperty("Item") 。
常數(key)
)
);
我想檢查的第一件事是,在填充字典時,以及在試圖取回值時,我都在使用同一個陣列實體。換句話說,下面的代碼:
expr = Lambda(
屬性(
Constant(dict)。
typeof(Dictionary<double[], List<double>>).GetProperty("Item")。
Constant(new double[] {1,2})
)
);
當你試圖編譯和呼叫它時,將拋出一個例外,即使兩個陣列中的值是一樣的,因為你在構建運算式時創建的陣列與字典中使用的鍵是不同的陣列:
(除非你在字典中使用了一個自定義的比較器,把兩個這樣的陣列實體當作同一個值。)
為了讀取常量的值,你需要深入到運算式樹中,最終將運算式轉化為
ConstantExpression,然后讀取Value屬性。
//將LambdaExpression的主體轉換為IndexExpression,以便我們可以讀取引數。
//將第一個引數轉換為ConstantExpression,這樣我們就可以讀取值。
var value = ((ConstantExpression)((IndexExpression)(expr.Body)).Arguments[0] ).Value。
Console.WriteLine(
((double[])value).Length
);
你將使用的確切的轉換和屬性呼叫將取決于你的運算式樹的精確結構。
請注意,在 Visual Studio 中進行除錯時,您可以在不提前知道精確結構的情況下在屬性中進行鉆取。
(免責宣告:我已經撰寫了相關的庫。)
另外,您可以使用ExpressionTreeToString 庫,代碼如下:
// using ExpressionTreeToString;
//expr包含一個運算式。
Console.WriteLine(
expr.ToString("Textual tree", "C#")
);
回傳一個描述運算式樹和評估常量的字串。
Lambda (Func<List<double> >)
- 身體 - 索引 (List<double>) = #List<double>
- Object - Constant (Dictionary<double[], List<double>>) = #Dictionary<double[], List<double> >
- Arguments[0] - Constant (double[]) = new[] { 1, 2 }
uj5u.com熱心網友回復:
我認為問題出在 如果你確定所請求的 在你的除錯器中停止,并添加一些測驗代碼來除錯你的問題。在這段代碼中,從 dictionary 中獲取任何鍵,例如第一個鍵。為這個鍵創建一個副本。
現在你知道firstKey和testKey是兩個不同的陣列,它們具有相同的長度和值。firstKey是Dictionary中的一個鍵。testKey不是,盡管它是一個陣列,具有與firstKey相同的長度和值。下面的測驗代碼應該可以通過: 現在你想用你運算式中的鍵做什么?你想用作鍵的 如果你的要求是一個不同的陣列,但具有相同的長度和值,也應該找到這個元素,那么下面的方法應該可以通過: 如果這沒有通過,那么你就知道問題的原因:Dictionary 使用了不正確的 Enumerable.SequenceEqual并沒有事先檢查長度。為了提高效率,我增加了對長度的檢查。
對于字典來說,一個合適的 什么是哈希碼?
你選擇什么樣的哈希函式取決于你使用什么樣的雙陣列作為鍵:如果它們是短陣列,那么考慮使用所有的值來計算哈希。如果你的鍵包含1000個雙數,那么使用它們全部來計算哈希值可能會太慢。也許你有什么想法,你希望你的鍵在哪方面有所不同。如果它們中的大多數以相同的前四個值開始,請考慮不要在你的哈希函式中使用它們。
考慮只檢查陣列的前幾個元素:
標籤: 上一篇:LINQile陣列拆分
double[]/code>是一個參考變數。
在創建Dictionary時傳入適當的EqualityComparer將解決這個問題。
對代碼進行除錯
。
double[] 在你的字典中,試著按照下面的方法進行除錯,就在你試圖獲取字典項的上面的代碼中。
Dictionary<double[], List<double> > myDictionary = ...
double[] firstKey = myDictionary.Keys.FirstOrDefault()。
double[] testKey = firstKey.ToArray();
// firstKey和testKey是具有相同長度和值的陣列:
Debug.Assert(firstKey.SequenceEqual(testKey))。
// firstKey在字典中
Debug.Assert(myDictionary.Keys.Contains(firstKey))。
// testKey與firstKey不是同一個物件 Debug.Assert(!Objects.Keys.Contains(firstKey)).
Debug.Assert(!Object.ReferenceEquals(firstKey, testKey))。
double[]應該是同一個物件,還是可以是一個不同的物件,但具有相同的值?
// Dictionary使用一個比較器來測驗firstKey和testKey是否相等:
IEqualityComparer<double[]> comparer = myDictionary.Comparer;
Debug.Assert(comparer.Equals(firstKey, testKey);
IEqualityComparer<double[]>創建 EqualityComparer
class DoubleArrayEqualityComparer 。EqualityComparer<double[]>
{
public static IEqualityComparer<double[]> ValueComparer {get;} = new DoubleArrayEqualityComparer()。
public override bool Equals (double[] x。double[] y)。
{
///如果你認為x和y相等,則回傳true。
if (x == null) return y == null; // true if both null.
if (y == null) return false; // because x not null; //span>
if (Object.ReferenceEquals(x, y)) return true; //for efficiency:
///如果x和y有相同的長度,它們就相等。
//有相同的值,且順序相同:。
return x.Length == y.Length
&& x.SequenceEqual(y)。
}
GetHashCode是非常重要的。你想讓一個方法在 x 和 y 相同的情況下回傳相同的哈希碼,但如果它們不同,不同的哈希碼并不是必須的,但它可以提高查找效率。但是,計算哈希碼的時間不能太長,否則會降低效率。public abstract int GetHashCode (double[] x)
{
if (x == null) return 7844588; //只是一個數字。
//選擇兩個大的質數:; //選擇兩個大的質數:。
const int prime1 = ...;
const int prime2 = ...。
unchecked[/span
{
int hash = prime1 * x.Length.GetHashCode()。
foreach (double value in x)
{
hash = hash * prime2 value.GetHashCode()。
}
return hash;
}
foreach (double value in x。 Take(5))

