Use of System.Linq in case of IEnumerable<t>? - c#

I have an API which returns System.Collections.Generic.IEnumerable<t>, if I import(using) System.Linq. I am able to do Count() / ToList() on the returned object.
What would be the relation between those two(System.Collections.Generic, System.Linq), packages ?
Thanks
Pavan

IEnumerable<> is that relationship. Those methods (Count(), ToList()) are extension methods on IEnumerable<>
This means that anything that implements IEnumerable (IList, ICollection, Arrays) they all will have those methods. To use them you need to "import" those methods with Using System.Linq; statement
A simple extension method on String. can be
public static class StringExtensions
{
public static string CountWords(this string input )
{
return imnput.Split(new char[]{' '}).Length;
}
}

There is a static class Enumerable in the System.Linq namespace which provides the most of extension methods you use with IEnumerable<T> types.

Related

Why can't I use LINQ with WorkItemCollection

I am using the COM interface to TFS. (TeamFoundationServer.ExtendedClient v14.95.3). I am trying to use LINQ to iterate over the various collections. For example, this function works great:
public static IEnumerable<string> GetTitles(WorkItemCollection workItemList)
{
return from WorkItem item in workItemList select item.Fields["Title"].Value.ToString();
}
However, when I try to change to use the method syntax it fails:
public static IEnumerable<string> GetTitles2(WorkItemCollection workItemList)
{
return workItemList.Select(item => item.Fields["Title"].Value.ToString());
}
... gives me error "'WorkItemCollection' does not contain a definition for 'Select'..."
I have using System.Linq; in my file. And I am referencing System.Core.dll. The WorkItemCollection does implement IEnumerable. So why doesn't this work?
WorkItemCollection does only implement IEnumerable, but not IEnumerable<WorkItem>. The LINQ extensions are declared only for IEnumerable<T>, not for the non-generic IEnumerable.
What you can do is use OfType<T>():
public static IEnumerable<string> GetTitles2(WorkItemCollection workItemList)
{
return workItemList.OfType<WorkItem>()
.Select(item => item.Fields["Title"].Value.ToString());
}
Instead of OfType<T> you can also use Cast<T>. But if there is something other than a WorkItem in the sequence (which is probably never the case in this scenario), Cast<T> would throw an InvalidCastException while OfType<T> would ignore that element.
WorkItemCollection implements IEnumerable, not IEnumerable<T>. It's the latter, generic, interface that is the foundation of LINQ.
You can convert from one to the other using the Cast<T> extension method, however:
workItemList.Cast<WorkItem>.Select(item => ...

LINQ expression with generic class properties

I would like to pass an IQueryable and an array of ids to a method which filters the IQueryable based on those ids.
As the ids can be either long's or int's it should be solved generically.
I came up with the following:
public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
return objects.Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}
Unfortunately I'm getting the exception:
LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object)' method, and this method cannot be translated into a store expression.
The exception is normal, as getting properties through reflection is something that clearly cannot be translated to SQL.
One thing I would try is to create a generic interface that exposes an Id property of a given type:
public interface HasId<T> {
T Id { get; set; }
}
Now you could declare your entity as implementing HasId<int>, for example, if the Id was of type int.
The next step is to modify your method like so:
public static IEnumerable<T> GetModified<TId, T>
(IQueryable<T> objects, TId[] ids) where T : class, HasId<TId>
{
return objects.Where(j => ids.Contains(j.Id));
}
Note the added generic restriction: where T : class, HasId<TId>. This enables you to write the simplified j.Id, which returns a TId value, instead of resorting to reflection.
Please note that I haven't run or tested this code; it's just an idea that I got when I saw your problem and I hope it helps.
Update:
Here's another possible solution that doesn't require that you declare interfaces or change your classes in any way:
public static IEnumerable<T> GetModified<TId, T>
(IQueryable<T> objects, TId[] ids, Expression<Func<T, TId>> idSelector)
where T : class
{
return objects.Where(j => ids.Contains(idSelector(j)));
}
What I've done here is add the Expression<Func<T, TId>> idSelector parameter, an expression that can return the Id of a given instance of T.
You would call the method like that:
var modified = GetModified(dbObjects, yourIdArray, entity => entity.Id);
(only the third parameter being new; keep the others as you have them now).
Again, I haven't tested if this works or even compiles, as I don't have a computer with VS here :(.
Entity Framework doesn't support some of the .NET methods such as GetValue() since it does not translate to SQL (which is the code actually executed to the IQueryable. Try calling ToList to get the CLR object before doing reflection:
public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
return objects.ToList().Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}

Do we have a "Contains" method in IEnumerable

I have a class in my code that is already deriving from IEnumerable.
I was wondering if there is a way that I can use a "Contains" method on its instnaces to look for a something in that list?
Do you really implement the non-generic IEnumerable, or the generic IEnumerable<T>? If you can possibly implement the generic one, your life will become a lot simpler - as then you can use LINQ to Objects, which does indeed have a Contains extension method.
Otherwise, you could potentially convert from the non-generic to generic using Cast or OfType, e.g.
bool found = nonGeneric.Cast<TargetType>().Contains(targetItem);
It would be nicer if you just implemented the generic interface to start with though :)
No, there's no such method in the IEnumerable<T> interface. There's an extension method though that you could use.
using System.Linq;
and then:
IEnumerable<string> foos = new[] { "foo", "bar", "baz" };
bool IsThereABar = foos.Contains("bar");
public static bool Contains<T>(this IEnumerable source, T value)
{
foreach (var i in source)
{
if (Equals(i, value))
return true;
}
return false;
}
If you want, you can add custom comparer as parameter ti extension method Contains

Where is the ToList() method? (IQueryable)

If I try this, it will work:
var query = myContextObject.Users.Where(u=>u.Name == "John");
query.ToList();
I'm able to call ToList and a lot of other extension methods.
But if I try this:
public List ConvertQueryToList(IQueryable query)
{
return query.ToList();
}
ToList won't be accessible, I'm guessing this is because ToList is an extension method, but then how is that ToList is attached in the first example?
Is it possible to access ToList in the second case?
You need to write it as:
public List<T> ConvertQueryToList<T>(IQueryable<T> query)
{
return query.ToList();
}
This will cause the IQueryable<T> to return the appropriate List<T>, since the Enumerable.ToList() method requires an IEnumerable<T> as input (which also works with IQueryable<T>, as IQueryable<T> inherits IEnumerable<T>).
That being said, there is really no reason to use it this way. You can always just call ToList() directly if you need to create a List<T> - abstracting inside of a second layer just confuses the API further.
If you're trying to convert a non-generic IQueryable interface, you would need to do something like:
public List<T> ConvertQueryToList<T>(IQueryable query)
{
return query.Cast<T>.ToList();
}
This would then require calling like:
var results = ConvertQueryToList<SomeType>(queryable);
Alternatively, if you want to leave this non-generic (which I wouldn't recommend), then you could use:
public ArrayList ConvertQueryToList(IQueryable query)
{
ArrayList results = new ArrayList();
results.AddRange(query.Cast<object>().ToList());
return results;
}
The first of your examples returns an IQueryable<T>, whereas in the second you're using IQueryable (without the Generic Type parameter).
You can check out the two completely different interfaces here and here.
Here is an extension method for this:
public static class ListHelper
{
public static IList ToList(this IQueryable query)
{
var genericToList = typeof(Enumerable).GetMethod("ToList")
.MakeGenericMethod(new Type[] { query.ElementType });
return (IList)genericToList.Invoke(null, new[] { query });
}
}
Here is a generic extension method for the case you are using IQueryable<>.
Of course it is not absolutely safe because the type could be wrong and the cast could fail. So please be careful if you use that method.
using System.Collections.Generic;
namespace System.Linq
{
public static class Extensions
{
public static List<T> ToList<T>(this IQueryable queriable)
{
return ((IQueryable<T>)queriable).ToList();
}
}
}

How can I implement NotOfType<T> in LINQ that has a nice calling syntax?

I'm trying to come up with an implementation for NotOfType, which has a readable call syntax. NotOfType should be the complement to OfType<T> and would consequently yield all elements that are not of type T
My goal was to implement a method which would be called just like OfType<T>, like in the last line of this snippet:
public abstract class Animal {}
public class Monkey : Animal {}
public class Giraffe : Animal {}
public class Lion : Animal {}
var monkey = new Monkey();
var giraffe = new Giraffe();
var lion = new Lion();
IEnumerable<Animal> animals = new Animal[] { monkey, giraffe, lion };
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Giraffe>();
However, I can not come up with an implementation that supports that specific calling syntax.
This is what I've tried so far:
public static class EnumerableExtensions
{
public static IEnumerable<T> NotOfType<T>(this IEnumerable<T> sequence, Type type)
{
return sequence.Where(x => x.GetType() != type);
}
public static IEnumerable<T> NotOfType<T, TExclude>(this IEnumerable<T> sequence)
{
return sequence.Where(x => !(x is TExclude));
}
}
Calling these methods would look like this:
// Animal is inferred
IEnumerable<Animal> fewerAnimals = animals.NotOfType(typeof(Giraffe));
and
// Not all types could be inferred, so I have to state all types explicitly
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Animal, Giraffe>();
I think that there are major drawbacks with the style of both of these calls. The first one suffers from a redundant "of type/type of" construct, and the second one just doesn't make sense (do I want a list of animals that are neither Animals nor Giraffes?).
So, is there a way to accomplish what I want? If not, could it be possible in future versions of the language? (I'm thinking that maybe one day we will have named type arguments, or that we only need to explicitly supply type arguments that can't be inferred?)
Or am I just being silly?
I am not sure why you don't just say:
animals.Where(x => !(x is Giraffe));
This seems perfectly readable to me. It is certainly more straight-forward to me than animals.NotOfType<Animal, Giraffe>() which would confuse me if I came across it... the first would never confuse me since it is immediately readable.
If you wanted a fluent interface, I suppose you could also do something like this with an extension method predicate on Object:
animals.Where(x => x.NotOfType<Giraffe>())
How about
animals.NotOf(typeof(Giraffe));
Alternatively, you can split the generic parameters across two methods:
animals.NotOf().Type<Giraffe>();
public static NotOfHolder<TSource> NotOf<TSource>(this IEnumerable<TSource> source);
public class NotOfHolder<TSource> : IHideObjectMembers {
public IEnumerable<TSource> NotOf<TNot>();
}
Also, you need to decide whether to also exclude inherited types.
This might seem like a strange suggestion, but what about an extension method on plain old IEnumerable? This would mirror the signature of OfType<T>, and it would also eliminate the issue of the redundant <T, TExclude> type parameters.
I would also argue that if you have a strongly-typed sequence already, there is very little reason for a special NotOfType<T> method; it seems a lot more potentially useful (in my mind) to exclude a specific type from a sequence of arbitrary type... or let me put it this way: if you're dealing with an IEnumerable<T>, it's trivial to call Where(x => !(x is T)); the usefulness of a method like NotOfType<T> becomes more questionable in this case.
If you're going to make a method for inference, you want to infer all the way. That requires an example of each type:
public static class ExtMethods
{
public static IEnumerable<T> NotOfType<T, U>(this IEnumerable<T> source)
{
return source.Where(t => !(t is U));
}
// helper method for type inference by example
public static IEnumerable<T> NotOfSameType<T, U>(
this IEnumerable<T> source,
U example)
{
return source.NotOfType<T, U>();
}
}
called by
List<ValueType> items = new List<ValueType>() { 1, 1.0m, 1.0 };
IEnumerable<ValueType> result = items.NotOfSameType(2);
I had a similar problem, and came across this question whilst looking for an answer.
I instead settled for the following calling syntax:
var fewerAnimals = animals.Except(animals.OfType<Giraffe>());
It has the disadvantage that it enumerates the collection twice (so cannot be used with an infinite series), but the advantage that no new helper function is required, and the meaning is clear.
In my actual use case, I also ended up adding a .Where(...) after the .OfType<Giraffe>() (giraffes also included unless they meet a particular exclusion condition that only makes sense for giraffes)
I've just tried this and it works...
public static IEnumerable<TResult> NotOfType<TExclude, TResult>(this IEnumerable<TResult> sequence)
=> sequence.Where(x => !(x is TExclude));
Am I missing something?
You might consider this
public static IEnumerable NotOfType<TResult>(this IEnumerable source)
{
Type type = typeof(Type);
foreach (var item in source)
{
if (type != item.GetType())
{
yield return item;
}
}
}

Categories