IEnumerable Null

  • Thread starter Thread starter shapper
  • Start date Start date
S

shapper

Hello,

I have the following extension to get a random item from a
IEnumerable.

private static Random random = new Random();
public static T Random<T>(this IEnumerable<T> target) {
Int32 position = random.Next(target.Count<T>());
return target.ElementAt(position);
} // Random

How can I "do nothing" if the target is empty?

This can happen for example when I filter a list of records using a
condition and no items satisfy that condition:

Product product = products.Where(p => p.Price > 1000).Random()

Thanks,
Miguel
 
shapper said:
I have the following extension to get a random item from a
IEnumerable.

private static Random random = new Random();
public static T Random<T>(this IEnumerable<T> target) {
Int32 position = random.Next(target.Count<T>());
return target.ElementAt(position);
} // Random

How can I "do nothing" if the target is empty?

This can happen for example when I filter a list of records using a
condition and no items satisfy that condition:

Product product = products.Where(p => p.Price > 1000).Random()

You would have to define what you mean by "do nothing" in this case. You
could return null, which in a query like the preceding would assign null to
product. If product is null after executing that query, you know that there
were no products in the list from where to choose one at random.

public static T Random<T>(this IEnumerable<T> target) {
if (target.Count==0) return null;
Int32 position = random.Next(target.Count<T>());
return target.ElementAt(position);
}
 
Alberto Poblacion said:
You would have to define what you mean by "do nothing" in this case. You
could return null, which in a query like the preceding would assign null
to product. If product is null after executing that query, you know that
there were no products in the list from where to choose one at random.

public static T Random<T>(this IEnumerable<T> target) {
if (target.Count==0) return null;

You can't do that, but the idea is sound. You must either return default(T)
or add a constraint where T : class.
 
in message





You can't do that, but the idea is sound.  You must either return default(T)
or add a constraint where T : class.

Yes, that was what I ended up doing:
if (target.Count<T>() == 0) return default(T);

I didn't know I could check the result as null.

Thanks,
Miguel
 
I didn't know I could check the result as null.

You can only check the result against null if T is a class (and not a
struct). That is why I was returning null rather than default(T) in my
example, on the assumption that you could constrain your generic to work
with classes:

public static T Random<T>(this IEnumerable<T> target) where T:class
{
if (...) return null;
...
}

Sorry about forgetting to add the constraint. Ben Voigt is, of course,
right in that it is needed.
If you need to use value-types then the solution is not terribly useful.
Default(T) if T is (for instance) an integer would return a zero, which
could perfectly well be a valid value for your Random selection, so it is
not a good value for comparing the result.
 
Back
Top