Lambda expression and class method - c#

I have a problem like this.
List<Absent> absent = new List<Absent>();
Console.WriteLine("--------------------------");
Console.Write("Please enter a full name> ");
string temp_str = Console.ReadLine();
absent.Where(x => x.Name == temp_str).Run(x = x.WriteConsoleTable());
How can I run a method after doing a filtering?
Absent is a Class which has a Name variable and WriteConsoleTable method.

Seems like you're looking for the ForEach extension method but you'll first need to call ToList on the IEnumerable sequence returned from the Where clause.
absent.Where(x => x.Name == temp_str)
.ToList()
.ForEach(x => x.WriteConsoleTable());
or you can iterate over the collection using the foreach construct.
i.e.
foreach (var item in absent.Where(x => x.Name == temp_str))
item.WriteConsoleTable();

You can try below options.
var absences = absent.Where(x => x.Name == temp_str);
foreach(var abs in absences)
{
abs.WriteConsoleTable();
}
or if you are sure you only need first match
var absence = absent.FirstOrDefault(x => x.Name == temp_str);
if(absence != null)
{
absence.WriteConsoleTable();
}

Related

Why EF code is not selecting a single column?

I have used this to pick just a single column from the collection but it doesn't and throws casting error.
ClientsDAL ClientsDAL = new DAL.ClientsDAL();
var clientsCollection= ClientsDAL.GetClientsCollection();
var projectNum = clientsCollection.Where(p => p.ID == edit.Clients_ID).Select(p => p.ProjectNo).ToString();
Method:
public IEnumerable<Clients> GetClientsCollection(string name = "")
{
IEnumerable<Clients> ClientsCollection;
var query = uow.ClientsRepository.GetQueryable().AsQueryable();
if (!string.IsNullOrEmpty(name))
{
query = query.Where(x => x.Name.Contains(name));
}
ClientsCollection = (IEnumerable<Clients>)query;
return ClientsCollection;
}
As DevilSuichiro said in comments you should not cast to IEnumerable<T> just call .AsEnumerable() it will keep laziness.
But in your case it looks like you do not need that at all because First or FirstOrDefault work with IQueryable too.
To get a single field use this code
clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => p.ProjectNo)
.First() // if you sure that at least one item exists
Or (more safe)
var projectNum = clientsCollection
.Where(p => p.ID == edit.Clients_ID)
.Select(p => (int?)p.ProjectNo)
.FirstOrDefault();
if (projectNum != null)
{
// you find that number
}
else
{
// there is no item with such edit.Clients_ID
}
Or even simpler with null propagation
var projectNum = clientsCollection
.FirstOrDefault(p => p.ID == edit.Clients_ID)?.ProjectNo;

Get Method is null off IQueryable (Entity Framework)

I'm trying to pass lambda expressions and a type to my DAL. I have this statement:
(entities).GetType().GetMethod("Where")
"entities" is the Table of entities on the DataContext.
When I run the statement I get a null even though Linq.Table inherits IQueryable.
Anyone have an idea?
Here is the entire method:
public object GetResultSet(Dictionary<Type, Func<object, bool>> values)
{
using (ICSDataContext db = DataContextFactory.CreateDataContext<ICSDataContext>(DataContexts.ICS))
{
foreach (var entry in values)
{
var property = db.GetType().GetProperty(entry.Key.Name + "s");
IQueryable entities = (IQueryable)property.GetValue(db, null);
var whereMethod = (entities).GetType().GetMethod("Where")
.MakeGenericMethod(Type.GetType(entry.Key.AssemblyQualifiedName));
return whereMethod.Invoke(entities, new object[] { entry.Value });
}
}
return null;
}
Thanks
As an alternative you could do something like
db.Set<Type>()
which will return you the DBSet of the appropriate type, with Where accessible without reflection. Also you may want to use Expression> rather than Func, expressions work on queryables where as funcs work on enumerables. If you pass a func into a Where clause it pulls the entire dbset down and processes it in memory.
Typed expressions are also a little easier to work with (intellesence, type checking).
Expression<Func<User,bool>> filter = c=>c.FirstName == "Bob";
As another alternative you can look into System.Linq.Dynamic, ScottGu has a write up on it here. The article and the code are old, but it works with EF 6. It allows things like
.Where("CategoryId=2 and UnitPrice>3")
From answer by LukeH under here:
var where1 = typeof(Queryable).GetMethods()
.Where(x => x.Name == "Where")
.Select(x => new { M = x, P = x.GetParameters() })
.Where(x => x.P.Length == 2
&& x.P[0].ParameterType.IsGenericType
&& x.P[0].ParameterType.GetGenericTypeDefinition() == typeof(IQueryable<>)
&& x.P[1].ParameterType.IsGenericType
&& x.P[1].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>))
.Select(x => new { x.M, A = x.P[1].ParameterType.GetGenericArguments() })
.Where(x => x.A[0].IsGenericType
&& x.A[0].GetGenericTypeDefinition() == typeof(Func<,>))
.Select(x => new { x.M, A = x.A[0].GetGenericArguments() })
.Where(x => x.A[0].IsGenericParameter
&& x.A[1] == typeof(bool))
.Select(x => x.M)
.SingleOrDefault();
Then this:
var gmi = where1.MakeGenericMethod(typeof(T));

Equivalent to search within IEnumerable with LINQ

Is there a shorter, elegant way to write the following using LINQ?
var actorName = string.Empty;
foreach (var myProperty in myProperties)
{
if (myProperty .PropertyName == "ActorName")
{
actorName = myProperty .PropertyValue;
break;
}
}
var actorName = myProperties
.FirstOrDefault(x => x.PropertyName == "ActorName")
.PropertyValue;
This would give a NPE if nothing could be found though (FirstOrDefault returns null as default).
To combat this, use two statements instead:
var actor = myProperties
.FirstOrDefault(x => x.PropertyName == "ActorName");
var actorName = actor == null ? string.Empty : actor.PropertyValue;
In addition to Jeroen's answer.. its safer to check for null first.. since FirstOrDefault returns null when there is nothing that matches:
var actor = myProperties
.FirstOrDefault(x => x.PropertyName == "ActorName");
if (actor != null)
actorName = actor.PropertyValue;
Pure LINQ version, for the hell of it, though I'd prefer Simon's answer.
var actorName = myProperties
.Where(x => x.PropertyName == "ActorName")
.Select(x => x.PropertyValue)
.Concat(new[]{ string.Empty })
.First();

c# remove item from list without knowing index number

I have a list with collection of my object:
List<MyObj> list = new List<MyObj>();
My function received MyObj as a parameter and i want to remove this object from the list like suggest here: c# remove item from list
private void remove(MyObj obj)
{
var itemToRemove = list.Where(x => x.fileName == obj.fileName);
if (itemToRemove != null)
list.Remove(itemToRemove);
}
Compiler error received:
cannot convert from 'System.Collections.Generic.IEnumerable' to 'namespace.MyObj'
Where() returns an IEnumerable<>
Try this:
private void remove(MyObj obj)
{
var itemToRemove = list.Where(x => x.fileName == obj.fileName);
if (itemToRemove.Any())
list.Remove(itemToRemove.First());
}
Better yet, as you're using List<>:
list.RemoveAll(x => x.fileName == obj.fileName);
Edit
Other solutions, that are all equally viable from the comments below. Pick your poison, though selfishly (and perhaps obviously) I prefer the readability and simplicity of the RemoveAll method:
Knittl:
list = list.Where(x => x.filename != obj.filename).ToList();
Jeroen van Langen:
var itemToRemove = list.Where(x => x.fileName == obj.fileName).FirstOfDefault();
if (itemToRemove != null)
list.Remove(itemToRemove);
You were mixed up between Where and FirstOrDefault:
private void remove(MyObj obj)
{
var itemToRemove = list.FirstOrDefault(x => x.fileName == obj.fileName);
if (itemToRemove != null)
list.Remove(itemToRemove);
}
There is no need for you to implement this method, the remove method of List already performs this operation as expected.
http://msdn.microsoft.com/en-us/library/cd666k3e.aspx
public bool Remove(
T item
)
You should use RemoveAll method exposed by list to remove all the matching elements -
private void remove(MyObj obj)
{
var itemToRemove = list.RemoveAll(x => x.fileName == obj.fileName);
}

Cannot assign void to an implicitly-typed local variable

var query = rep.GetIp() // in this line i have the error
.Where(x => x.CITY == CITY)
.GroupBy(y => o.Fam)
.Select(z => new IpDTO
{
IId = z.Key.Id,
IP = z.Select(x => x.IP).Distinct()
})
.ToList().ForEach(IpObj => IpObj.IP.ToList().ForEach(ip => PAINTIP(ip)));
When I run this code I have the error:
Cannot assign void to an implicitly-typed local variable
I googled and found that it is a type issue because foreach is not a LINQ function? I cannot understand where the void is!
ForEach() has type void.
Select() returns IEnumerable<T>, ToList() returns List<T>, etc.
so:
List<X> x = ...Select(x => x).ToList(); // List<T>
or
x.ForEach(x => x); // void
because you can't assign void to List<T>.
var query = rep.GetIp() // in this line i have the error
.Where(x => x.CITY == CITY)
.GroupBy(y => o.Fam)
.Select(z => new IpDTO
{
IId = z.Key.Id,
IP = z.Select(x => x.IP).Distinct()
});
foreach (var dto in query)
{
foreach (var ip in dto.IP)
{
PAINTIP(ip);
}
}
or
var query = ....
.SelectMany(z => z.Select(x => x.IP).Distinct());
foreach (var ip in query)
{
PAINTIP(ip);
}
ForEach() does not return anything. Its type is void.
Try replacing your ForEach() calls with Select().
I saw your other questions, wherein you have asked similar question for the same query. The code partially looks like this :
var Q = rep.GetIp()
.Where(x => x.CITY == CITY)
.GroupBy(y => o.Fam)
.Select(z => new IpDTO
{
IId = z.Key.Id,
IP = z.Select(x => x.IP).Distinct()
});
Looks like you have used the answer as such and you are trying to assign the returned value from the query to the variable "Q". Check out your previous post : syntax in LINQ IEnumerable<string>
As others have said, ForEach return type is "void". You should call "ForEach", once the variable "Q" is initialized with the collection.

Categories

Resources