Metoda rozszerzenia .AsQueryable()
zwraca instancję z EnumerableQuery<T>
wrapper class, jeśli jest wywoływana w przypadku czegoś, co nie było jeszcze IQueryable<T>
.
Ta klasa otoki ma właściwość .Enumerable
z dostępem internal
, która zapewnia dostęp do oryginalnego obiektu, na którym wywołano .AsQueryable()
. Więc mógłby to zrobić, aby odzyskać swój pierwotny słownika:
var dict = new Dictionary<int, int>();
dict.Add(1,1);
var q = dict.AsQueryable();
Type tInfo = q.GetType();
PropertyInfo pInfo = tInfo.GetProperties(BindingFlags.NonPublic |
BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Enumerable");
if (pInfo != null)
{
object originalDictionary = pInfo.GetValue(q, null);
Console.WriteLine(dict == originalDictionary); // true
}
Jest to jednak na ogół całkiem zły pomysł. internal
członkowie mają ograniczony dostęp z jakiegoś powodu i nie sądzę, że istnieje jakakolwiek gwarancja, że wewnętrzne wdrożenie .AsQueryable()
nie zmieni się w którymś momencie w przyszłości. Najlepiej jest znaleźć sposób na udostępnienie oryginalnego słownika lub stworzyć nowy.
Jedną z możliwości obejścia (co nie jest wielki) jest zrobić własne klasy otoki do przeprowadzenia słownika wzdłuż:
private class DictionaryQueryHolder<TKey, TValue> : IQueryable<KeyValuePair<TKey, TValue>>
{
public IDictionary<TKey, TValue> Dictionary { get; private set; }
private IQueryable<KeyValuePair<TKey, TValue>> Queryable { get; set; }
internal DictionaryQueryHolder(IDictionary<TKey, TValue> dictionary)
{
Dictionary = dictionary;
Queryable = dictionary.AsQueryable();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Queryable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Expression Expression
{
get { return Queryable.Expression; }
}
public Type ElementType
{
get { return Queryable.ElementType; }
}
public IQueryProvider Provider
{
get { return Queryable.Provider; }
}
}
To byłoby zarówno działać jako otoczka do słownika w IQueryable<T>
i zapewniać dostęp do oryginalnego słownika . Ale z drugiej strony, każdy, kto próbuje pobrać słownik musiałby wiedzieć, jakie były parametry rodzaju ogólnego (na przykład <string, string>
, <int, string>
, itp.), Aby móc go pomyślnie obsłużyć.
Podpowiedź z prywatnym polem 'Obliczalne' działała.Zawarłem nawet rezerwę w moim kodzie ('if (pInfo == null), następnie stwórz nowy słownik i ręcznie dodaj KeyValuePairs'), aby zachować kompatybilność z przyszłymi wersjami. –