自定义Linq扩展语法

时间:2008-12-09 06:02:36

标签: c# linq generics extension-methods

我编写了一个从列表中获取给定数量的随机记录的函数。目前我可以做类似的事情:

IEnumerable<City> cities = db.Cites.GetRandom(5);

(其中db是我连接到SQL Server DB的DataContext)

目前,我在每个需要随机记录的实体中都有这样的函数:

public partial class City
{

    public static IEnumerable<City> GetRandom(int count)
    {
        Random random = new Random();
        IEnumerable<City> cities = DB.Context.Cities.OrderBy( c => random.Next() ).Take(count);

        return cities;
    }

}

它工作正常,但我希望它是通用的,因此它可以适用于任何表,甚至任何项目列表。我尝试了一种扩展方法,如:

    public static IEnumerable<T> GetRandom<T>( this Table<T> table, int count)
    {
        Random random = new Random();
        IEnumerable<T> records = table.OrderBy(r => random.Next()).Take(count);

        return records;
    }

但我明白了:

  Error 1   The type 'T' must be a reference type in order to use it as parameter 'TEntity' in the generic type or method 'System.Data.Linq.Table' 

突出显示GetRandom<T>

我不明白这里的问题是什么。有人可以清理正确的语法吗?

4 个答案:

答案 0 :(得分:6)

我喜欢随机顺序函数的概念,它可以应用于任何IEnumerable,如下所示:

public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
{
    Random rnd = new Random();
    return source.OrderBy(t => rnd.Next());
}

...

IEnumerable<City> cities = db.Cites.Randomize().Take(5);

答案 1 :(得分:5)

如果您正在与数据库通信,则可能需要在数据库中执行随机提取。使用LINQ-to-SQL,您可以(对于较小的卷)通过指向NEWID的[Function](在数据上下文中)执行此操作:

     [Function(Name="NEWID", IsComposable=true)] 
     public Guid Random() 
     { 
         return Guid.NewGuid(); 
     } 

然后在查询中通过:

     ctx.Log = Console.Out; 
     var query = from x in ctx.Suppliers 
                 orderby ctx.Random() 
                 select x; 
     var results = query.ToArray(); 

给出了TSQL(这里使用Northwind):

SELECT [t0].[SupplierID], [t0].[CompanyName], [t0].[ContactName], 
[t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], 
[t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax], [t0].[HomePage] 
FROM [dbo].[Suppliers] AS [t0] 
ORDER BY NEWID() 

你可以将它与Take(1)等混合使用。

但它在实体框架中不起作用。

答案 2 :(得分:4)

JaredPar,我认为你不能用通用定义中的:class来做到这一点。

我认为这是定义类型约束的正确方法:

public static IEnumerable<T> GetRandom<T>( this Table<T> table, int count) where T : class {
  ...
}

有关类型约束的更多信息here

答案 3 :(得分:0)

试试这个

public static IEnumerable<T> GetRandom<T>( this Table<T> table, int count) where T : class {
  ...
}