How to cast C#'s linq WHERE statement? - c#

I have a class Literal and a Tag is inheriting from it.
I would like to do the following but I am getting
Unable to cast object of type 'WhereListIterator`1[Core.Literal]' to type 'System.Collections.Generic.List`1[Core.Tag]'.
private List<Literal> literals;
public List<Tag> Tags
{
get { return (List<Tag>)literals.Where(x => x is Tag); }
}
thanks

You would be better off doing:
literals.OfType<Tag>().ToList();
This gives you a List<Tag>.
You can also do:
var asList = new List<Tag>(literals.OfType<Tag>());
Casting simply does not work because LINQ works in terms of either IEnumerable<T> or IQueryable<T> which neither use List as a backing implementation for the results. The second method I posted uses a constructor overload of List<T> the takes in an IEnumerable<T> as its initial collection of objects. Also in this scenario the OfType<T> method from LINQ is a much cleaner, shorter form of essentially filtering a list with Where(x -> x is T).
Also, OfType<T> in this scenario is a much better idea, because the result is an IEnumerable<T> of your target type. Where(x => x is T) will return an IEnumerable<T> of the original source's type. So that's why (List<Tag>)literals.Where(x => x is Tag).ToList() emit an error for invalid casts.
More information on ToList
More information on OfType

literals.Select(x => x as Tag).Where(x => x != null).ToList()
Note that this will return new list. You won't be able to do where and modify original list by this. Also this can be done like this: literals.OfType<Tag>().ToList() and it will return IList<Tag>
Update: modified type

List<Tag>)literals.Where(x => x is Tag).ToList();
or even better :
literals.OfType<Tag>();
then you can create a new list from it:
new List<Tag>(literals.OfType<Tag>());

Depending on the effect you want you could do this:
public List<Tag> Tags
{
get { return literals.Where(x => x is Tag).ToList(); }
}
Do realize that this is not a cast but the creation of a list!

How about adding ToList()?
Your getter becomes: literals.Where(x => x is Tag).ToList();

try the following:
literals.Where(x => x is Tag).Cast<Tag>().ToList();
it works if Tag is derived from Literal

The Where method returns the same type as the source, so you would have to cast each item, then use the ToList method to create a list from the result:
return literals.Where(x => x is Tag).Select(x => (Tag)x).ToList();
You can also us the OfType method:
return literals.OfType<Tag>().ToList();

Related

Create Object from Anonymous Type

I'm using EntityFramework to a list of objects from the database and I'm using Anonymous Types to eventually return the right object. Because there are several functions that has to do this 'Anonymous type conversion' I want to extract this to functions.
I can create a function to create a dynamic but can't create a function that converts a dynamic in a specific type because if the function has a parameter that contains a dynamic, the return type is a dynamic type too.
This works:
List<SomeObject> list = list
.Select(i => GetAnonymousType(i))
.Select(i => new SomeObject {Item1 = i.Item1, Item2 =i.Item2}).ToList();
This doesn't:
List<SomeObject> list = list
.Select(i => GetAnonymousType(i))
.Select(i => CreateSomeObjectFromDynamic(i)).ToList();
private static SomeObject CreateSomeObjectFromDynamic(dynamic i)
{
return new SomeObject {Item1 = i.Item1, Item2 = i.Item2};
}
See: https://dotnetfiddle.net/zLFlur
Is there a way I can use a function like: CreateSomeObjectFromDynamic to return the right type?
try this:
list = list
.Select(i => GetAnonymousType(i))
.Select(i => CreateSomeObjectFromDynamic(i) as SomeObject).ToList();
According to provided code at fiddle, your problem is not with CreateSomeObjectFromDynamic method, your problem is with GetAnonymousType method. This method returns dynamic and .NET cannot handle it. The compliler error says that:
Cannot implicitly convert type
'System.Collections.Generic.List<dynamic>' to
'System.Collections.Generic.List<SomeObject>'
Even changing query to
list = list
.Select(i => CreateSomeObjectFromDynamic(GetAnonymousType(i)))
.ToList();
will produce the same error. But, if you change return type of GetAnonymousType method to object as below:
private static object GetAnonymousType(SomeObject i)
{
return new { Item1 = i.Item1, Item2 = i.Item2 };
}
your problem will be solved. But, this works in memory, I am not sure that it will successfully be translated into SQL if you try to use it with IQueryable for example. Also, I do not recomend using dynamic, even though it works after chaning return type to object your code does not seem right. If you make a bit effort, I am sure that you will find another way, for example using inheritance, generics and etc.

PredicateBuilder Returns No Rows

This code correctly returns one row:
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where t.GetInterfaces().Contains(typeof(TInterface))
&& t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`')
select t);
}
However, when I use PredicateBuilder, I get zero rows:
var compiledPredicate = CompiledPredicate<TInterface>();
_loadedAssemblies.ForEach(x =>
{
foundTypes.AddRange(from t in x.GetTypes()
where compiledPredicate.Invoke(typeof(TInterface))
select t);
}
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
// True means all records will be returned if no other predicates are applied.
var predicate = PredicateBuilder.True<Type>();
// Get types that implement the interface (T).
predicate = predicate.And(t => t.GetInterfaces().Contains(typeof(T)));
// If the config file includes filtering by base class, then filter by it.
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
predicate = predicate.And(t => t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`'));
}
return predicate.Compile();
}
Someone suggested creating a copy of my loop variable, but I tried that and I still get zero rows. I'm not sure why using PredicateBuilder returns no rows. Any idea what I'm missing?
The change that you mentioned in comments (foundTypes.AddRange(x.GetTypes().AsQueryable().Where(compiledPredicate));) had nothing at all to do with the fact that you were using AsQueryable. In the first case you're passing in a hard coded type to each call of your predicate, in the second you're passing the given item from the sequence. Had you removed the AsQueryable and used Enumerable.Where it would also work, or had you passed the current item, rather than a hard coded type, when invoking it that would also work.
So you can simply do:
foundTypes.AddRange(x.GetTypes().Where(compiledPredicate));
Also, when creating the predicate, there's no need to do as much work as you're doing. Expressions take a fair amount of extra work to deal with. With linq to objects you only need to deal with delegates, which are much less finicky.
private static Func<Type, bool> CompiledPredicate<T>() where T : class
{
Func<Type, bool> predicate = t => t.GetInterfaces().Contains(typeof(T));
if (!string.IsNullOrWhiteSpace(_baseClass))
{
Type baseClass = Type.GetType(_baseClass);
return t => predicate(t) &&
t.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`');
}
return predicate;
}

how to convert from IEnumerable<type> to type?

I am using EF 4 with repository pattern which has the generic query method shown below:
public IEnumerable<T> Query(Expression<Func<T, bool>> filter)
{
return objectSet.Where(filter);
}
I know I can select a complete object like this:
context.PeriodRepository.Query(a => a.EntityId == selectedEntityId);
But I want to pass a Linq query that returns it as type instead of IEnumerable<type> using a LINQ expression without changing the method. Please advise me how to do that.
Use the First() or FirstOrDefault() methods and pass in a predicate to find the element you want if it is not the first.
A Query describes the operations performed on the list; you must perform the query to get the result(s).
Using .ToList()/.ToArray() will return all items that match the query. Use .First() to get the first item that matches or .FirstOrDefault() to get the first item or the default value for no matches.
The default value for a class is null.
I think your code should be like this:
var myMatch = context.PeriodRepository
.Query(a => a.EntityId == selectedEntityId)
.First();
Also note that, First() will throw an exception when there is no match.

C#: projection - accessing a given string property in a collection of objects in the same way as a List<string>

a quick projection question. I have a collection of objects (unchangeditems) in a test method, and would like to ensure they match my 'expected' elements. As shown you could do it by element, but this isn't ideal. I'm sure its possible to use projection to get down to the string variable (LMAA_CODE - don't ask about the capitals!) along the lines of the bottom line below. I'd appreciate a hand.
Thanks!
// Works but not very elegant
Assert.AreEqual(result.unchangedItems[0].LMAA_CODE,expectedunchangedItems[0]);
Assert.AreEqual(result.unchangedItems[1].LMAA_CODE,expectedunchangedItems[1]);
Assert.AreEqual(result.unchangedItems[2].LMAA_CODE,expectedunchangedItems[2]);
Assert.AreEqual(result.unchangedItems[3].LMAA_CODE,expectedunchangedItems[3]);
// ?Can something like this be done? eg result.unchangedItems => result.unchangedItems.LMAA_CODE
Assert.IsTrue(Enumerable.SequenceEqual(result.unchangedItems.LMAA_CODE, expectedunchangedItems));
You were almost there already, just added a projection to LMAA_CODE:
Assert.IsTrue(Enumerable.SequenceEqual(result.unchangedItems.Select( x=> x.LMAA_CODE),
expectedunchangedItems));
You can use LINQ and Zip:
Assert.IsTrue(result.unchangedItems.Zip(expectedunchangedItems, (actual, expected) => actual.LMAA_CODE == expected).All(value => value));
What about:
for (int i = 0; i < result.unchangedItems.Count; i++) {
Assert.AreEqual(result.unchangedItems[i].LMAA_CODE, expectedUnchangedItems[i]);
}
You can also do:
Assert.IsFalse(result.unchangedItems.Where((r,i) => expectedUnchangedItems[i] != r.LMAA_CODE).Any())
.Any() will return true if the filtered sequence contains elements, and it shouldn't. That's why you call IsFalse. If your testing framework (or whatever you are using) does not have that, you can always do Assert.AreEqual(____, false).
You could also use a "Zip" extension method.
Assert.AreEqual(result.unchangedItems.Count, expectedunchangedItems.Count);
result.unchangedItems.Zip(expectedunchangedItems, (a, b) => Tuple.Create(a, b))
.ForEach(p => Assert.AreEqual(p.Item1.LMAA_CODE, p.Item2));
This way, the exception reports which value was not expected. The Zip() method is included in .NET 4, but I personally prefer to use my own, and of course you'd want a ForEach() too:
// I actually have a Pair<A,B> struct that I prefer to use, but
// KeyValuePair or Tuple works almost as well.
public static IEnumerable<Tuple<A, B>> ZipTuples<A, B>(this IEnumerable<A> a, IEnumerable<B> b)
{
IEnumerator<A> ea = a.GetEnumerator();
IEnumerator<B> eb = b.GetEnumerator();
while (ea.MoveNext() && eb.MoveNext())
yield return new Tuple<A, B>(ea.Current, eb.Current);
}
public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
foreach (T item in list)
action(item);
}
Usage:
Assert.AreEqual(result.unchangedItems.Count, expectedunchangedItems.Count);
result.unchangedItems.ZipTuples(expectedunchangedItems)
.ForEach(p => Assert.AreEqual(p.Item1.LMAA_CODE, p.Item2));

C# - AsEnumerable Example

What is the exact use of AsEnumerable? Will it change non-enumerable collection to enumerable
collection?.Please give me a simple example.
From the "Remarks" section of the MSDN documentation:
The AsEnumerable<TSource> method has no effect
other than to change the compile-time
type of source from a type that
implements IEnumerable<T> to
IEnumerable<T> itself.
AsEnumerable<TSource> can be used to choose
between query implementations when a
sequence implements IEnumerable<T> but also has a different set
of public query methods available. For
example, given a generic class Table
that implements IEnumerable<T> and has its own methods such
as Where, Select, and SelectMany, a
call to Where would invoke the public
Where method of Table. A Table type
that represents a database table could
have a Where method that takes the
predicate argument as an expression
tree and converts the tree to SQL for
remote execution. If remote execution
is not desired, for example because
the predicate invokes a local method,
the AsEnumerable<TSource>
method can be used to hide the custom
methods and instead make the standard
query operators available.
If you take a look in reflector:
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source)
{
return source;
}
It basically does nothing more than down casting something that implements IEnumerable.
Nobody has mentioned this for some reason, but observe that something.AsEnumerable() is equivalent to (IEnumerable<TSomething>) something. The difference is that the cast requires the type of the elements to be specified explicitly, which is, of course, inconvenient. For me, that's the main reason to use AsEnumerable() instead of the cast.
AsEnumerable() converts an array (or list, or collection) into an IEnumerable<T> of the collection.
See http://msdn.microsoft.com/en-us/library/bb335435.aspx for more information.
From the above article:
The AsEnumerable<TSource>(IEnumerable<TSource>) method has no
effect other than to change the compile-time type of source from a type
that implements IEnumerable<T> to IEnumerable<T> itself.
After reading the answers, i guess you are still missing a practical example.
I use this to enable me to use linq on a datatable
var mySelect = from table in myDataSet.Tables[0].AsEnumerable()
where table["myColumn"].ToString() == "Some text"
select table;
AsEnumerable can only be used on enumerable collections. It just changes the type of the collection to IEnumerable<T> to access more easily the IEnumerable extensions.
No it doesn't change a non-enumerable collection to an enumerable one. What is does it return the collection back to you as an IEnumerable so that you can use it as an enumerable. That way you can use the object in conjunction with IEnumerable extensions and be treated as such.
Here's example code which may illustrate LukeH's correct explanation.
IEnumerable<Order> orderQuery = dataContext.Orders
.Where(o => o.Customer.Name == "Bob")
.AsEnumerable()
.Where(o => MyFancyFilterMethod(o, MyFancyObject));
The first Where is Queryable.Where, which is translated into sql and run in the database (o.Customer is not loaded into memory).
The second Where is Enumerable.Where, which calls an in-memory method with an instance of something I don't want to send into the database.
Without the AsEnumerable method, I'd have to write it like this:
IEnumerable<Order> orderQuery =
((IEnumerable<Order>)
(dataContext.Orders.Where(o => o.Customer.Name == "Bob")))
.Where(o => MyFancyFilterMethod(o, MyFancyObject));
Or
IEnumerable<Order> orderQuery =
Enumerable.Where(
dataContext.Orders.Where(o => o.Customer.Name == "Bob"),
(o => MyFancyFilterMethod(o, MyFancyObject));
Neither of which flow well at all.
static void Main()
{
/*
"AsEnumerable" purpose is to cast an IQueryable<T> sequence to IEnumerable<T>,
forcing the remainder of the query to execute locally instead of on database as below example so it can hurt performance. (bind Enumerable operators instead of Queryable).
In below example we have cars table in SQL Server and are going to filter red cars and filter equipment with some regex:
*/
Regex wordCounter = new Regex(#"\w");
var query = dataContext.Cars.Where(car=> article.Color == "red" && wordCounter.Matches(car.Equipment).Count < 10);
/*
SQL Server doesn’t support regular expressions therefore the LINQ-to-db providers will throw an exception: query cannot be translated to SQL.
TO solve this firstly we can get all cars with red color using a LINQ to SQL query,
and secondly filtering locally for Equipment of less than 10 words:
*/
Regex wordCounter = new Regex(#"\w");
IEnumerable<Car> sqlQuery = dataContext.Cars
.Where(car => car.Color == "red");
IEnumerable<Car> localQuery = sqlQuery
.Where(car => wordCounter.Matches(car.Equipment).Count < 10);
/*
Because sqlQuery is of type IEnumerable<Car>, the second query binds to the local query operators,
therefore that part of the filtering is run on the client.
With AsEnumerable, we can do the same in a single query:
*/
Regex wordCounter = new Regex(#"\w");
var query = dataContext.Cars
.Where(car => car.Color == "red")
.AsEnumerable()
.Where(car => wordCounter.Matches(car.Equipment).Count < 10);
/*
An alternative to calling AsEnumerable is ToArray or ToList.
*/
}
The Enumerable.AsEnumerable method can be used to hide a type's custom implementation of a standard query operator
Consider the following example. we have a custom List called MyList
public class MyList<T> : List<T>
{
public string Where()
{
return $"This is the first element {this[0]}";
}
}
MyList has a method called Where which is Enumerable.Where() exact same name. when I use it, actually I am calling my version of Where, not Enumerable's version
MyList<int> list = new MyList<int>();
list.Add(4);
list.Add(2);
list.Add(7);
string result = list.Where();
// the result is "This is the first element 4"
Now how can I find the elements which are less than 5 with the Enumerable's version of Where?
The answer is: Use AsEnumerable() method and then call Where
IEnumerable<int> result = list.AsEnumerable().Where(e => e < 5);
This time the result contains the list of elements that are less than 5

Categories