从dict获取原始字典.AsQueryable()

Jür*_*ock 7 .net c# dictionary iqueryable

我有一个通用字典传递给一个只接受IQueryable参数的方法

是否可以将可查询转换回原始字典?我并不是说要创建一个新词典.ToDictionary(...)

private static void Main()
{

    var dict = new Dictionary<int, int>();
    dict.Add(1,1);

    SomeMethod(dict.AsQueryable());

}

public static void SomeMethod(IQueryable dataSource)
{
    // dataSource as Dictionary<int, int> --> null
    var dict = dataSource.???
}
Run Code Online (Sandbox Code Playgroud)

我知道在这个简单的例子中,这没有多大意义.但是在大图中我有一个接口,它要求我返回IQueryable一个dataSource.在实现上返回一个字典.在我的代码中的另一个地方,我有处理dataSources的类.

处理器知道dataSource将是一个Dictionary,但是如果我已经有一个Dictionary,我不想要创建另一个Dictionary的开销.

JLR*_*she 6

.AsQueryable()扩展方法返回的实例,EnumerableQuery<T>包装类,如果它被称为的东西,是不是已经是一个IQueryable<T>.

此包装类具有一个.Enumerable具有internal访问权限的属性,该属性提供对.AsQueryable()调用的原始对象的访问.所以你可以这样做来取回原来的字典:

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
}
Run Code Online (Sandbox Code Playgroud)

但是,这通常是一个非常糟糕的主意.internal由于某种原因,成员的访问权限受到限制,我认为没有任何保证内部实施.AsQueryable()在将来的某个时候不会发生变化.因此,最好的办法是找到一种方法使原始字典可访问,或者继续创建一个新字典.


一种可能的解决方法(不是很好)是使您自己的包装类携带字典:

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

这既可以作为字典的包装,IQueryable<T>也可以提供对原始字典的访问.但在另一方面,任何人试图检索字典必须知道什么泛型类型参数为(例如<string, string>,<int, string>等),以便顺利投放.