Chris
Chris

Reputation: 7621

Generic method issue

I'm trying to implement a LINQ-to-SQL extension method that will simply get a random row. This is my code:

public static T RandomRow(this IQueryable<T> query)
{
    Random rand = new Random();
    int row = rand.Next(0, query.Count());
    return query.Skip(row).First();
}

Problem is, the query.Count() and query.Skip() have an error of 'The type arguments for method '...' cannot be inferred from usage. Try specifying the type arguments explicitly'. It works fine if I modify the T to be of a specific object, but it'd be great to use this method with any database object.

Any ideas?

Upvotes: 1

Views: 59

Answers (2)

Jon Skeet
Jon Skeet

Reputation: 1503479

Your method looks like it should be generic:

// Note the <T> after the method name
public static T RandomRow<T>(this IQueryable<T> query)

Either that, or put it in a generic class.

You might also want to use the ElementAt method instead of Skip/First.

EDIT: As CodeInChaos notes, your use of Random is problematic too. See my article on random numbers for more information.

Upvotes: 4

CodesInChaos
CodesInChaos

Reputation: 108880

You have another problem too: You create a new instance of Random on each call to this method. This means you will get the same result if you call it in quick succession, which breaks encapsulation.

You have several ways to avoid this problem:

  1. Pass in an instance of Random, and have the calling code manage its life time
  2. Use a static field containing an instance of Random. You'll need to take care of thread safety by either using locking or using a thread static field
  3. Make it an instance method and make Random an instance field.
  4. Use manual seeding with a better seed than the default seed.

Upvotes: 0

Related Questions