C# LINQ—在C中运行时更改数据源(和LINQ提供程序)#

C# LINQ—在C中运行时更改数据源(和LINQ提供程序)#,c#,linq,C#,Linq,我正在设计一个数据信息接口层。我希望这一层的用户不知道数据源,仍然使用LINQ语法的优点。我希望使用标准LINQ提供程序作为该层的实现,并希望避免编写自定义LINQ提供程序 考虑下面的例子 信息接口层声明如下 interface IMyData { int Intdata { get; } double DoubleData { get; } } interface IMyDataProviderLayer { IQueryable< IMyData >

我正在设计一个数据信息接口层。我希望这一层的用户不知道数据源,仍然使用LINQ语法的优点。我希望使用标准LINQ提供程序作为该层的实现,并希望避免编写自定义LINQ提供程序

考虑下面的例子

信息接口层声明如下

interface IMyData
{
    int Intdata { get; }
    double DoubleData { get; }
}


interface IMyDataProviderLayer
{
    IQueryable< IMyData > Context { get; }
}
接口实现将访问来自真实数据源的数据,并且需要使用标准LINQ提供程序

有可能像上面那样做吗?即使数据源有标准的LINQ实现,我也需要从头开始实现LINQ提供程序吗? 还是有更好的方法来实现我在这里的目标?
提前谢谢。

我想你是在找一种类似的。您将拥有如下界面:

public interface IMyRepository
{
    IEnumberable<MyObject> GetObjects();
}
您还可以在存储库中使用
IQueryable
而不是
IEnumerable
。我解释了两者之间的一些区别。但基本上,IQueryable生成SQL并发送到数据库,而IEnumerable调用数据库,然后在内存中执行查询


通过这种方式,您可以将ORM从LINQ改为SQL,再改为实体框架,或者任何可以将查询抽象为IQueryable或IEnumerable的东西。

看起来您的
IMyDataProviderLayer
基本上就是您的“存储库”抽象。您可以使用该接口的一个实现或模拟,该接口返回一个
列表
备份
IQueryable
,而不是使用访问数据库的普通提供程序

您可以通过插入一个定制的
IQueryable
实现来实现这一点,该实现包装了
IList

public class QueryableList<T> : System.Linq.IQueryable<T>
{
    private IList<T> _data;

    public QueryableList()
    {
      _data = new List<T>();
    }

    public QueryableList(IList<T> data)
    {
      _data = data;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    public Expression Expression
    {
        get { return Expression.Constant(_data.AsQueryable()); }
    }

    public IQueryProvider Provider
    {
        get { return _data.AsQueryable().Provider; }
    }

    public Type ElementType
    {
        get { return typeof(T); }
    }
}

编辑:

在我写了这篇文章后不久,我又回到这里,意识到我制作了IQueryable列表包装器来解决一个不同的问题。实际上,您完全忽略了这一点,只需执行以下操作:

using System.Linq;

IQueryable<IMyData> mydata = new List<IMyData>()
    {
        new MyData() { Intdata = 5, DoubleData = 1.2 },
        new MyData() { Intdata = 2, DoubleData = 6.8 }
    }.AsQueryable();
使用System.Linq;
IQueryable mydata=新列表()
{
new MyData(){Intdata=5,DoubleData=1.2},
new MyData(){Intdata=2,DoubleData=6.8}
}.AsQueryable();
调用
.AsQueryable()
将该列表转换为IQueryable,而不是使用上面的包装器


抱歉给您带来困惑:)

哇。。。太快了。我将用您的答案进行实际实现的实验。但从逻辑上讲,我认为这是正确的。感谢您提供的存储库模式链接。我也在考虑类似的问题,但无法插入现成的IQueryable。你的例子清楚地说明了这一点。我也会尝试这个解决方案。肖恩·麦克莱恩(Shawn McLean)的解决方案很简单,但我觉得你的解决方案更优雅一些。我还考虑使用依赖注入来实现实际数据提供者的运行时绑定,您的解决方案听起来更适合这种情况。谢谢
var dataCollection = from data in repository.GetObjects()
                             where data.Intdata == 5
                             select data;
public class QueryableList<T> : System.Linq.IQueryable<T>
{
    private IList<T> _data;

    public QueryableList()
    {
      _data = new List<T>();
    }

    public QueryableList(IList<T> data)
    {
      _data = data;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    public Expression Expression
    {
        get { return Expression.Constant(_data.AsQueryable()); }
    }

    public IQueryProvider Provider
    {
        get { return _data.AsQueryable().Provider; }
    }

    public Type ElementType
    {
        get { return typeof(T); }
    }
}
// Make a mock data access layer, that is backed by a List.
var mockedDataLayer = new Mock<IMyDataProviderLayer>();
mockedDataLayer.SetupGet(x => x.Context, new QueryableList<IMyData>()
    {
        new MyData() { Intdata = 5, DoubleData = 1.2 },
        new MyData() { Intdata = 2, DoubleData = 6.8 },
    });

// Now we can use this.
var dataCollection = from data in mockedDataLayer.Object.Context
                     where data.Intdata == 5
                     select data;
using System.Linq;

IQueryable<IMyData> mydata = new List<IMyData>()
    {
        new MyData() { Intdata = 5, DoubleData = 1.2 },
        new MyData() { Intdata = 2, DoubleData = 6.8 }
    }.AsQueryable();