Lambda expression does not work in object list - c#

I have an object list and I can add record with that sentence:
List<DragerClass.Alarm> alarms = new List<DragerClass.Alarm>();
public void createAlarm(int i, int[] alarms)
{
alarms.Add(new DragerClass.Alarm(i, DateTime.Now, DragerClass.Dedector.Dedector_Name[i] + " UNDER RANGE"))`;
}
But when I try to remove an item, it behaves like lambda expression doesn't support:
public void removeAlarm(int i)
{
alarms.Remove(x => x.Dedector_No == i);
}
I see that message when I stand on the code
cannot convert lambda expression to type
'Drager_GasDedection.DragerClass.Alarm' because it is not a delegate
type
I'm using Visual Studio 2010 and I also added System.Data.Entity in references. But still same. Thanks for any help.

Take a look at the methods of List<T>. The method Remove(T) simply expects one element. If it is found in the list it is removed, otherwise nothing is done. Remove is not looking for a Predicate<T> that it will check.
RemoveAll(Predicate<T>) however expects a predicate. So you need to call:
alarms.RemoveAll(x => x.Dedector_No == i);
You also have to change = to == in your code since otherwise you are performing an assignment instead of an equality check. Furthermore note that the method will remove all alarms with the given detector number, not just the first.

Related

using lambda expression to set combo box data source c# windows Forms application

given the following instance variable
cboBankAccountId.DataSource = db.BankAccounts.Where(x => x.BankAccountId).ToList();
Lets assume that my table names and properties are all correct... can somebody explain to me why this way of assigning a data source does not work with a windows form application.
However i seen in other posts that the following (and what i used in my project) works.
Now is this simply because of how a combo boxes properties are assigned in a windows form vs a web form??
cboBankAccountId = db.BankAccounts;
cboBankAccountId.ValueMember = "BankAccountId";
cboBankAccountId.DisplayMember = "FullName";
thanks...
and happy thanksgiving!
A ComboBox control's data source can be a database, a Web service, or an object that can later be used to generate data-bound controls.
The problem with your code is in your lambda expression.
The extension method "Where" in your case expects a delegate of type Func<BankAccounts, bool>. i.e., you must pass a delegate which takes BankAccounts as input and gives bool as output which is used to filter your result.
So, if you wanted to find out BankAccounts with an Id of 1, your lambda expression would look like this:
cboBankAccountId.DataSource = db.BankAccounts.Where(x => x.BankAccountId == 1).ToList();
If you are new to Lambda Expressions, you can also translate it as:
cboBankAccountId.DataSource = db.BankAccounts.Where((BankAccounts x) =>
{
return x.BankAccountId == 1;
}).ToList();
or, the full version:
public bool Filter(BankAccountId id)
{
bool filterPassed;
if(id == 1)
filterPassed = true;
else
filterPassed = false;
return filterPassed;
}
cboBankAccountId.DataSource = db.BankAccounts.Where(Filter).ToList();
As you can see, all you need to pass to the Where method is a method which can be used for filtering out the result. Each item in the list is then run through this method and only the ones that pass the test are returned. That's how the Where extension method in LINQ works.

IEnumerable Expression-Bodied Member C#

I have a get-only property in C# that returns an IEnumerable. If that property will only ever yield once, then I could define my property like so:
public IEnumerable Derp {
get { yield return new SomeObject(); }
}
But how would I do this with a C#6 expression-bodied member? The following approaches do NOT work:
// These definitions do NOT work
public IEnumerable Derp => yield return new SomeObject();
public IEnumerable Derp => yield new SomeObject();
returning compiler error CS0103: "The name 'yield' does not exist in the current context". Is a yielding expression-bodied member even possible in C#6? How about in C#7?
I'm aware that an IEnumerable member that only returns once looks smelly, but I'm mainly just curious. I came across this situation while experimenting with the NUnit TestCaseSource API, trying to provide a method that yields only one test case. I could also see this being relevant to Unity developers who want to define an expression-bodied method to be called with StartCoroutine().
Anyway, thanks in advance for your thoughts!
Expression-bodied functions/properties can't have statements... You can't, for example:
static int Test(int x) => if (x > 0) x else 0;
or even
static int Test(int x) => return x;
yield is a statement... You can't use it :-)
Note that you can:
IEnumerable<SomeObject> Derp => new[] { new SomeObject() };
From the Roslyn github page, New Language Features in C# 6:
2.1 Expression bodies on method-like members
Methods as well as user-defined operators and conversions can be given an expression body by use of the “lambda arrow”:
The effect is exactly the same as if the methods had had a block body with a single return statement.
For void returning methods – and Task returning async methods – the arrow syntax still applies, but the
expression following the arrow must be a statement expression (just as is the rule for lambdas):
So there is an exception for void returning methods, but still it only covers calling methods (you can => Console.WriteLine("Hello"); but you can't => if ()).

Lambda works in FindAll, but not when using it as an Func (or Expression)

The code below won't compile:
Func<Person, bool> theLambda = (p) => p.Year >= 1992;
foreach (Person pers in PersonList.FindAll(theLambda))
{
Console.WriteLine(pers.Name);
}
public class Person
{
public string Name { get; set; }
public int Year { get; set; }
public Person(string Name, int Year )
{
this.Name = Name; this.Year = Year;
}
}
However, if I replace variable "theLambda" directly with the lambda, then it works just fine. What's going on here? (Be gentle, I'm a novice). Thank you so much in advance!
(1) I read the error message, but it doesn't mean anything to me.
(2) Yes, I can make it work with a Predicate by using the compile() keyword, but that's not the issue here.
Edit: why would anyone downvote this? The question wasn't that bad at all as the problem domain is not of a logic nature indeed. Really people.
It works because if you declare the lambda inline the compiler implicitly assigns it the right type, i.e. Predicate<Person>. You don't have to explicitly tell the compiler the lambda type as it knows already that it should take a Person and return a bool if you call FindAll on a List<Person>.
foreach (Person pers in PersonList.FindAll(p => p.Year >= 1992))
{
Console.WriteLine(pers.Name);
}
You can also use Enumerable.Where - LINQ method with the same functionality to make it a bit more readable:
foreach (Person pers in PersonList.Where(p => p.Year >= 1992))
{
Console.WriteLine(pers.Name);
}
From msdn:
When writing lambdas, you often do not have to specify a type for the
input parameters because the compiler can infer the type based on the
lambda body, the parameter’s delegate type, and other factors as
described in the C# Language Specification. For most of the standard
query operators, the first input is the type of the elements in the
source sequence. So if you are querying an IEnumerable<Customer>, then
the input variable is inferred to be a Customer object
The confusing part is that a Predicate is logically a Func that takes an object of some type T and returns a bool, but for some reason this typing doesn't work and you have to use Predicate<T>. Declaring the lambda function inline avoids this confusion as you just write the lambda body and let the compiler infer the type on its own.
The FindAll expects a Predicate and not a Function as seen in the method definition Array.FindAll<T> Method (T[], Predicate<T>)
When you try to pass theLambda it is trying to pass a Function, when the method expects a Predicate. You can instead try defining theLambda as
Predicate<Person> theLambda = (p) => p.Year >= 1992;
A Predicate is a Function that returns a Boolean and that is what is required by the FindAll method to filter the results.
Based on the answer here, you can do the following.
foreach (Person pers in PersonList.FindAll(new Predicate<Person>(theLambda)))

Expression parsing - Possible to get array of property names as string?

Is it possible to complete this method? Is it possible in the latest version of C#? Thinking about this as a DSL to configure a system for watching for certain property changes on certain objects.
List<string> list = GetProps<AccountOwner>(x => new object[] {x.AccountOwnerName, x.AccountOwnerNumber});
// would return "AccountOwnerName" and "AccountOwnerNumber"
public List<string> GetProps<T>(Expression<Func<T, object[]>> exp)
{
// code here
}
In C# 6, you'd use:
List<string> list = new List<string>
{
nameof(AccountOwner.AccountOwnerName),
nameof(AccountOwner.AccountOwnerNumber)
};
Before that, you could certainly break the expression tree apart - the easiest way of working out how is probably to either use an expression tree visualizer, or use the code you've got and put a break point in the method (just make it return null for now) and examine the expression tree in the debugger. I'm sure it won't be very complicated - just a bit more than normal due to the array.
You could possibly simplify it using an anonymous type, if you use:
List<string> list = Properties<AccountOwner>.GetNames(x => new {x.AccountOwnerName, x.AccountOwnerNumber});
Then you could have:
public static class Properties<TSource>
{
public static List<string> GetNames<TResult>(Func<TSource, TResult> ignored)
{
// Use normal reflection to get the properties
}
}
If you don't care about the ordering, you could just use
return typeof(TResult).GetProperties().Select(p => p.Name).ToList();
If you do care about the ordering, you'd need to look at the names the C# compiler gives to the constructor parameters instead - it's a bit ugly. Note that we don't need an expression tree though - we only need the property names from the anonymous type. (An expression tree would work just as well, admittedly.)
Without c# 6 and nameof, you could get a property name from a expression tree like:
using System.Linq.Expressions;
//...
static string GetNameOf<T>(Expression<Func<T>> property)
{
return (property.Body as MemberExpression).Member.Name;
}
Using it like:
GetNameOf(() => myObject.Property);
Not directly usable for an array of objects, but you could make an overload to take an array of expressions... something like:
static string[] GetNameOf(IEnumerable<Expression<Func<object>>> properties)
{
return properties.Select(GetNameOf).ToArray();
}
And use it like
GetNameOf(
new Expression<Func<object>>[]
{
() => x.AccountOwnerName,
() => x.AccountOwnerNumber
}
);
Demonstrating fiddle: https://dotnetfiddle.net/GsV96t
Update
If you go this route, the original GetNameOf for a single property won't work for value types (since they get boxed to object in the Expression and now the expression uses Convert internally). This is easily solvable by changing the code to something like:
static string GetNameOf<T>(Expression<Func<T>> property)
{
var unary = property.Body as UnaryExpression;
if (unary != null)
return (unary.Operand as MemberExpression).Member.Name;
return (property.Body as MemberExpression).Member.Name;
}
Updated fiddle: https://dotnetfiddle.net/ToXRuu
Note: in this updated fiddle I've also updated the overloaded method to return a List instead of an array, since that's what was on your original code

Using Lambda Expression on an ObservableCollection

in my Silverlight 4 application, I have an ObservableCollection which consists of objects of a class and is defined by an interface:
interface myInterface()
{
string Name { get; set; }
string Value { get; set; }
}
class myClass() : myInterface
{
...
}
ObservableCollection<myInterface> _collection;
Before adding a new element to the collection, I want to make sure, that the Name-Property does not already exists within the current collection elements.
As I cannot work with contains, I currently iterate through all elements and check each element manually.
private bool CollectionContainsElement(string name2CheckAgainst)
{
foreach (myInterface item in _collection)
if (item.Name.Equals(name2CheckAgainst))
return true;
return false;
}
I have read that this can also be achieved via a Lambda Expression, so I wrote the following:
if (!_collection.Contains(p => p.Name == name2CheckAgainst))
{
...
But now I get an error, saying that the "lambda expression could not be converted to the Type "myInterface", because it is no delegate-type". (Wording may differ, as I translated it from the german version)
I'm not sure what I have to change to make it work. using System.Linq; is included. And the second question (or maybe the primary question): I have read, that the runtime changes from O(1) for the Contains()-method to O(n) - which isn't faster than my current check. So does it even make sense to change it to using the lambda? And finally, is there probably another method in checking for an existing Name-Property in my class?
Thanks in advance,
Frank
You don't have to write a Contains method, the Any method of Linq is already doing that:
if (!_collection.Any(p => p.Name == name2CheckAgainst))
If you want to use a Lambda, you have to change the prototype of your Contains method to accept a Lambda (a lambda is just an alternative way to write an anonymous function):
private bool CollectionContainsElement(Func<myInterface, bool> lambda)
{
foreach (myInterface item in _collection)
if (lambda(item))
return true;
return false;
}
Using a lambda here doesn't change the complexity of your function, it's O(n) in both case. So it's just a matter of preference.
You can use the Linq Any() method. Which is useable like so:
if (!_collection.Any(p => p.Name == name2CheckAgainst))
{
}
The reason why the contains method is O(1) is that under the covers it loads your collection into a HashTable (or similar) and uses the hash code (followed by a call to Equals) to check whether an element is present.
Contains is not a LINQ extension and therefore you can't use lambda expressions with it. It was designed to check if provided object exists in the list.
As others have said, Any is a equivalent lambda-expression compatible extension method

Categories

Resources