Linq Enumerable.Where Func not getting called - c#

I have the following code
var filteredList = posData.Where(x => MyFilter(x, ruleDetail.wheres)).ToList();
where MyFilter is defined as
static bool MyFilter(Dictionary<string,string> dict, List<WhereClause> wheres)
{
if (dict["x"] == "y")
return true;
else
return false;
}
posData is of type
List<dictionary<string,string>>
I have a breakpoint in MyFilter function but the code execution never gets there. I am looking for MyFilter to do some custom analysis based on the wheres parameter. This is only a small part of the code. Please help me figure out why is MyFilter not getting called ?

Your code should work fine and as expected. The only reason that it wouldn't work in your case is if posData is empty, so make sure that it's not.
I tried it with this code (which is basically the same as yours):
static void Main()
{
// create test collection
var posData = new List<Dictionary<string,string>>();
var test = new Dictionary<string,string>();
test.Add("x", "y");
posData.Add(test);
// call the Where function
var filteredList = posData.Where(x => MyFilter(x)).ToList();
Console.WriteLine(filteredList.Count); // outputs "1"
}
static bool MyFilter(Dictionary<string,string> dict)
{
Console.WriteLine("hello"); // outputs "hello"
return dict["x"] == "y";
}

Related

How to create FUNC Action List with Parameters and Return Values

I am trying to create my first list of actions that I will be able to check a status within the passed object.
But I can't get it to work - its giving me an error on the return type. But if I change the return type to what it wants - then I can't pass values down.
Sample code:
public class Class1
{
public Main()
{
var decisionObject = new DecisionObject();
var decisionList = new List<Func<DecisionObject, DecisionObject>>
{
Method1(decisionObject),
Method2(decisionObject),
Method3(decisionObject)
};
var exitLoop = false;
foreach (var method in decisionList)
{
decisionObject = method(decisionObject);
switch (decisionObject.Status)
{
case Status1:
exitLoop = true;
break;
case Status2:
case Status3:
case Status4:
break;
}
if (exitLoop) break;
}
}
public Func<DecisionObject, DecisionObject> Method1(DecisionObject
decisionObject)
{
decisionObject = SomeOtherMethod(decisionObject);
return decisionObject;
}
}
What am I missing here?
If I'm not mistaken, Method1,Method2, and Method3 are simply supposed to accept a decision object and return a different one. So they would be defined like this (hopefully this is straightforward to you):
DecisionObject Method1(DecisionObject input)
{
var output = SomeMethod(input);
return output;
}
You then want to put all these methods into a list and execute them. To put them into a list, put the method names in the code without parentheses. That tells C# that you want a reference to the method itself, rather than the result of invoking the method.
var decisionList = new List<Func<DecisionObject, DecisionObject>>
{
Method1, //Do not invoke-- just store a reference to the method
Method2,
Method3
};
You can then invoke them by passing the decision object in:
foreach (var func in decisionList)
{
var result = func(decisionObject);
}
The key thing here to remember is that when you put parentheses after a symbol, it tells C# to invoke it. So don't put parentheses if all you want is a reference to the method itself.
decisionObject = SomeOtherMethod(decisionObject)
Isn't probably returning a func but a value.
You could do this:
public Func<DecisionObject, DecisionObject> Method1()
{
var myFunc = (myObject) => SomeOtherMethod(myObject);
return myFunc;
}
That will create and returns a new func that expects one parameter and invokes SomeOtherMethod.
Please note that the parameter of Method1 isn't needed in this approach and so I removed it.

c# - Using input parameter of lambda expression in if statement

I have if statement like this:
if (myList.Any(x => s.Contains(x))
{
//some code here
}
in which I check if there is a string in myList which is contained in a string s.
Is it somehow possible to get the element x of this list and use it in the if statement showed above (in "//some code here" part), when the condition is met?
Thank you.
Switch from Any to FirstOrDefault, that will return the item that matched the test or null if no item was matched.
var found = myList.FirstOrDefault(x => s.Contains(x));
if (found != null)
{
//some code here
}
If null could be considered a "valid value" for a element in myList you can create a extension method TryFirst
public static class ExtensionMethods
{
public static bool TryFirst<T>(this IEnumerable<T> #this, Func<T, bool> predicate, out T result)
{
foreach (var item in #this)
{
if (predicate(item))
{
result = item;
return true;
}
}
result = default(T);
return false;
}
}
This would let you do
string foundString;
var wasFound = myList.TryFirst(x => s.Contains(x), out foundString);
if (wasFound)
{
//some code here
}
and tell the difference between a null in your list and a default result.
The above two methods only act on the first item on the list that the Contains will match, if you want to act on all the items use a Where( clause and a foreach
foreach(var item in myList.Where(x => s.Contains(x))
{
//some code here
}
You must promise you will not use the following code and use one of the other options first
You can also do your stated question, it is possible to get a variable assigned to inside lambada. However this can not be done with expression lambadas, only with statement lambadas.
string matachedString = null;
if (myList.Any(x => { var found = s.Contains(x);
if(found)
matachedString = x;
return found;
});
{
//some code here
}
But only do this option as a last resort, use one of the more appropriate methods like FirstOrDefaut or write a custom method like TryFirst first.
I'd use foreach/Where()for this, even if I'm only expecting 0 or 1 result:
foreach (var item in myList.Where(x => s.Contains(x)))
{
//some code here
}

Alter the parameters of an instance of an Action object

Say I have the following code:
void Main()
{
SeveralCalls(() => CallWithParams("test"),
() => CallWithParams("AnotherTest"));
}
public void SeveralCalls(params Action[] methodsToCall)
{
foreach (var methodToCall in methodsToCall)
{
methodToCall();
}
}
public void CallWithParams(string someValue, string otherValue = null)
{
Console.WriteLine("SomeValue: " + someValue);
Console.WriteLine("OtherValue: " + otherValue);
}
Is it possible to supply a value for the parameter otherValue for the calls to CallWithParams by only modifying the SeveralCalls method?
I want to inject a value into the calls if it comes via the SeveralCalls method.
As a bit of background, I am working on code to call tabled paramed stored procedures (as a way to integrate my WCF Service into legacy code). The call normally makes its own connection to the database, but I need to be able to group several calls in a transaction.
If I do that, then I need each call to use the same SqlConnection object. The SeveralCalls method would allow me to group calls together, start a transaction, and (hopefully) pass the connection to the method that will actually make the call to the sproc.
You can do this with Expressions. Everywhere you're currently using Action, use Expression<Action> instead. You can then inspect the expression object, create a new one and use the new one instead of the initial expression. Here's an example. Note the ModifyExpression method which verifies that the expression is a lambda that invokes the CallWithParams method. In this example, I'm looking at the parameters and if the second is missing or null, I programmatically create a new lambda expression with the second parameter equal to "overridden value". Note that I had to add the null values into the CallWithParams lambdas. Evidently you can't use expressions with default parameters, so I just had to give it the default value in the lambdas.
static void Main()
{
SeveralCalls(() => CallWithParams("test", null),
() => CallWithParams("AnotherTest", null));
}
public static void SeveralCalls(params Expression<Action>[] expressions)
{
foreach (var expression in expressions)
{
var modifiedExpression = ModifyExpression(expression);
var action = modifiedExpression.Compile();
action();
}
}
private static Expression<Action> ModifyExpression(Expression<Action> expression)
{
var lambda = expression as LambdaExpression;
if (lambda == null)
return expression;
var call = lambda.Body as MethodCallExpression;
if (call == null)
return expression;
var method = typeof(Program).GetMethod("CallWithParams");
if (call.Method != method)
return expression;
if (call.Arguments.Count < 1 || call.Arguments.Count > 2)
return expression;
var firstArgument = call.Arguments[0];
var secondArgument = (call.Arguments.Count == 2 ? call.Arguments[1] : null);
var secondArgumentAsConstant = secondArgument as ConstantExpression;
if (secondArgumentAsConstant == null || secondArgumentAsConstant.Value == null)
secondArgument = Expression.Constant("overridden value");
var modifiedCall = Expression.Call(method, firstArgument, secondArgument);
var modifiedLambda = Expression.Lambda<Action>(modifiedCall);
return modifiedLambda;
}
public static void CallWithParams(string someValue, string otherValue = null)
{
Console.WriteLine("SomeValue: " + someValue);
Console.WriteLine("OtherValue: " + otherValue);
}
No, I don't believe this is possible. () => CallWithParams("test") is compiled to code that calls CallWithParams("test", null), with both of those values hardcoded. There's no way (besides, potentially, some complicated reflection and/or IL emitting) to modify this in SeveralCalls.
If you could modify Main as well, this might be a good way to do it:
void Main()
{
SeveralCalls("Some other string",
otherValue => CallWithParams("test", otherValue),
otherValue => CallWithParams("AnotherTest", otherValue));
}
public void SeveralCalls(string otherValue, params Action<string>[] methodsToCall)
{
foreach (var methodToCall in methodsToCall)
{
methodToCall(otherValue);
}
}
public void CallWithParams(string someValue, string otherValue = null)
{
Console.WriteLine("SomeValue: " + someValue);
Console.WriteLine("OtherValue: " + otherValue);
}
Or:
string otherValue = null;
void Main()
{
SeveralCalls(() => CallWithParams("test", this.otherValue),
() => CallWithParams("AnotherTest", this.otherValue));
}
public void SeveralCalls(params Action[] methodsToCall)
{
this.otherValue = "Some other string";
foreach (var methodToCall in methodsToCall)
{
methodToCall();
}
}
// added static just to clarify that the otherValue here is separate from the
// one in 'this'
public static void CallWithParams(string someValue, string otherValue = null)
{
Console.WriteLine("SomeValue: " + someValue);
Console.WriteLine("OtherValue: " + otherValue);
}
No. The Action objects your SeveralCalls() method receives are opaque. You cannot discover that their invocation code happens to call CallWithParam() without using reflection and CIL inspection and disassembly.
(Doing so would be rather complicated, and would also likely not be guaranteed to be portable since the details of how the C# compiler converts lambdas into anonymous types are not guaranteed not to change. In other words it is possible only by assuming non-public implementation details of the C# compiler.)
A better solution might be to put the CallWithParams() method inside a class that contains a field or property which you can change. Then you can set this field/property as desired, and any future calls to CallWithParams() will behave accordingly. The viability/sanity of this probably depends on what you're really trying to accomplish.
In my opinion, wanting to inject a parameter into lambdas is indicative of a flawed design, so if you can share more details about why you want to do this, maybe we can help find a better solution.
No, your method accepts a generic Action. There's no way for it to be sure that the code it's calling receives one or two parameters or what type that parameter is.
You could accept an Action<string> inside the SeveralCalls-method and then pass in that value in the invocation:
void Main()
{
SeveralCalls(extra => CallWithParams("test", extra),
extra => CallWithParams("AnotherTest", extra));
}
public void SeveralCalls(params Action<string>[] methodsToCall)
{
foreach (var methodToCall in methodsToCall)
{
methodToCall("some other param");
}
}
public void CallWithParams(string someValue, string otherValue = null)
{
Console.WriteLine("SomeValue: " + someValue);
Console.WriteLine("OtherValue: " + otherValue);
}

LINQ c# unique element in collection

I have a method that is supposed to check whether there is exactly one element in a collection that holds true for some predicate (given as a Func).
public bool ExistsUnique(Func<T, bool> p)
{
var tempCol = from i in MyCollection where p(i) select i;
return (tempCol.Count() == 1);
}
The problem with this is that when a second element that also holds true for the predicate
is found (for example two of the same string exists in a collection) the count is still 1. Which means it either overrides the first element or never adds the second because it already exists.
Any ideas as to how I can fix this method?
thx
/Peter
You can use the Single() method provided by LINQ like this:
public bool ExistsUnique(Func<T, bool> p)
{
try
{
var temp = myCollection.Single(x => p(x));
}
catch(Exception e)
{
// log exception
return false;
}
return true;
}
"Returns the only element of a sequence that satisfies a specified condition, and throws
an exception if more than one such element exists."
From http://msdn.microsoft.com/en-us/library/bb535118.aspx
EDIT
To avoid throwing an exception, you may also use the SingleOrDefault() method:
public bool ExistsUnique(Func<T, bool> p)
{
return myCollection.SingleOrDefault(x => p(x)) != null;
}
There must be some other problem. I'd suspect your predicate. For example, this returns a count of 2, as expected:
List<string> MyCollection = new List<string>()
{
"hello",
"hello"
};
var tempCol = from i in MyCollection where i == "hello" select i;
int count = tempCol.Count();
I doubt that it's the way you're calling it, either. The following works (returns false):
static List<string> MyCollection = new List<string>()
{
"hello",
"hello"
};
static bool ExistsUnique(Func<string, bool> p)
{
var tempCol = from i in MyCollection where p(i) select i;
return tempCol.Count() == 1;
}
static void DoIt()
{
bool isUnique = ExistsUnique((s) => s.Equals("hello"));
Console.WriteLine(isUnique);
}
Are you sure tempCol has looped completely through MyCollection?
is Count() a method that forces the complete loop or is it lazy?
Does for example tempCol.ToList().Count give the correct result?
This implementation would make it so you don't have to actually enumerate the entire collection, so will save you some execution time.
public bool ExistsUnique(Func<T, bool> p)
{
return MyCollection.Where(i => p(i)).Take(2).Count() == 1;
}
The Take(2) limits the Count to only enumerate the first two meeting the criteria.

Perform Assert.AreMatch() to deep compare properties in two objects

I am writing tests against our Caching mechanism and I want to be sure that what goes into the cache is the same as what comes out, ie that all properties match. Here is a fictional example of how I would like it to work
[Test]
public void add_client_model_member_to_cache_then_retreve()
{
//arrange
MemcachedClient client = new MemcachedClient();
Member member = GetMember();
client.Store(StoreMode.Set, "membertest", member);
// act
var result = client.Get<Member>("membertest");
// assert
Assert.AreMatch(result, member);
}
It is not feasible to perform Assert.AreEqual on each property as there will be many of these tests with many properties in each.
Wow, thanks Jon. I think you answered that in under one minute. Here are my resulting solution for any interested parties. I implemented as Jon suggested (I think) however I got into a little trouble with array properties and as such my solution only handles arrays of ints (all I currently require).
It also got to be a fairly slippery slope if I try to check deeper than one level. I am sure this can be achieved however for my purposes it is not required.
private bool AreMatch(object initial, object result)
{
if (initial.Equals(result))
return true;
foreach (var property in initial.GetType().GetProperties())
{
var initialPropValue = property.GetValue(initial,null);
var resultPropValue = result.GetType().GetProperty(property.Name).GetValue(result,null);
if (property.PropertyType.IsArray)
{
if ((initialPropValue != null && resultPropValue != null) && !Enumerable.SequenceEqual((int[])initialPropValue, (int[])resultPropValue))
return false;
}
else if (!object.Equals(initialPropValue, resultPropValue))
{
return false;
}
else if (initialPropValue != null && property.PropertyType.IsClass)
{
// Don't go deeper than one level, this got me into trouble
//if (!AreMatch(initialPropValue, resultPropValue))
// return false;
}
}
return true;
}
The method above can be used in the following situations
[Test]
public void cached_result_is_same_as_original()
{
//arrange
Member member = GetMember();
client.Store(StoreMode.Set, "membertest", member);
// act
var result = client.Get<Member>("membertest");
// assert
Assert.IsTrue(AreMatch(member, result));
}
[Test]
public void cached_result_is_same_as_original()
{
//arrange
Member member = GetMember();
client.Store(StoreMode.Set, "membertest", member);
// act
var result = client.Get<Member>("membertest");
result.FirstName = "Result is different";
// assert
Assert.IsFalse(AreMatch(member, result));
}
Well, you could certainly write something to recurse through all the properties, and call object.Equals on the result of fetching the property value from the expected and actual ones. Use Type.GetProperties() to get the properties themselves, and PropertyInfo.GetValue to get the value.
It'll be somewhat crude, but you could always tweak it if necessary.

Categories