I want to make a function that checks if a value matches all conditions that are Listed somewhere. I've been thinking how to do it with delegates, but nothing came into my mind. Because I dont know how to check if every function in delegate returns true. Here's code I tried. it gives me method name expected error.
public List<bool> conditionsToCheck;
public bool isWordValid(string wordToCheck)
{
bool[] checkResults = new bool[conditionsToCheck.Count];
for (int i = 0; i < conditionsToCheck.Count; i++)
{
checkResults[i] = conditionsToCheck[i](wordToCheck);
}
//then I check if all bool values in checkResults contain true
}
public void AddConditionToCheck(bool condition)
{
conditionsToCheck.Add(condition);
}
Thank you in advance!
Something like this?
public List<Func<string,bool>> conditionsToCheck = new();
public bool isWordValid(string wordToCheck) =>
!conditionsToCheck.Any(c => !c(wordToCheck));
public void AddConditionToCheck(Func<string,bool> condition) =>
conditionsToCheck.Add(condition);
The example code is not tested, but intended to show how it works.
Each condition is a function that must be evaluated later. Here's how to use it:
obj.AddConditionToCheck(w => w.Length > 4);
The isWordValid() function then calls all those conditions and stops at the first that returns false (no need to continue).
Docs:
https://learn.microsoft.com/en-us/dotnet/api/system.func-2?view=net-5.0
https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.any?view=net-5.0
Okay lets list some conditions just for the sake of example:
public bool IsCool(string str)
{
return str == "Cool";
}
public bool IsLong(string str)
{
return str.Length > 100;
}
public bool IsQuestion(string str)
{
return str.Contains("?");
}
We can group these in a collection of delegates like so:
# Required to use Func Delegate
using System;
// Func<string, bool> means a function that accepts a string parameter and returns a bool
var rules = new List<Func<string, bool>>();
// Notice we aren't doing IsCool(), we don't want to invoke the method
// but rather pass the method itself as a parameter to Add()
rules.Add(IsCool);
rules.Add(IsLong);
rules.Add(IsQuestion);
And then check if all of the functions return true:
var str = "Bleh";
var pass = true;
foreach(var rule in rules)
pass = pass && rule.Invoke(str);
Unneeded but cool improvements
We can use the Linq library to make it read nicer:
using System.Linq;
var pass = rules.All(rule => rule.Invoke(str));
And if we are feeling wild, add an extension method:
public static class String Extensions
{
public static bool Satisfies(this String str, params Func<string, bool>[] rules)
{
return rules.All(rule => rule.Invoke(str);
}
}
"Woah!".Satisfies(IsLong, IsCool, IsQuestion);
Related
Trying to use C#'s Action / Func functionality to execute a list of methods with various parameters. Here is some sample code (that does not compile) that illustrates what I am trying to do:
class Program
{
static void Main(string[] args)
{
List<Action> actions = getRelevantRules();
foreach (Action a in actions)
{
String result = a.Invoke();
Console.WriteLine("Got.." + result);
}
}
public static List<Action> getRelevantRules()
{
List<Action> relevant = new List<Action>();
relevant.Add(ruleCombintIt("Str1","Str2"));
relevant.Add(ruleEchoIt("Str1"));
relevant.Add(ruleChangeCase("Str1",true));
return relevant;
}
public static String ruleEchoIt(String val)
{
return val;
}
public static String ruleChangeCase(String val, Boolean toUpper)
{
return (toUpper) ? val.ToUpper() : val.ToLower();
}
public static String ruleCombintIt(String val1, String val2)
{
return val1 + val2;
}
}
I know that the "Action" cannot be used as it does not return a result. However, I do need to be able to return the result. I have tried (without success to see how I could achieve this using Func and Delegate)
Key requirements:
1) Need to be able to get the String return value
2) Need to be able to set the actual parameter values of the function at the time I add the item to the list.
3) Need to be able to handle cases (as shown) where each method being added to the list may have different parameters.
Can what I am looking to do be done?
Thanks for the help!
It looks like what you actually want is a List<Func<string>> - a Func<string> takes no arguments and returns a string.
Working code:
public class Program
{
public static void Main(string[] args)
{
List<Func<string>> actions = getRelevantRules();
foreach (var a in actions)
{
String result = a();
Console.WriteLine("Got.." + result);
}
}
public static List<Func<string>> getRelevantRules()
{
List<Func<string>> relevant = new List<Func<string>>();
relevant.Add(() => ruleCombintIt("Str1","Str2"));
relevant.Add(() => ruleEchoIt("Str1"));
relevant.Add(() => ruleChangeCase("Str1",true));
return relevant;
}
public static String ruleEchoIt(String val)
{
return val;
}
public static String ruleChangeCase(String val, Boolean toUpper)
{
return (toUpper) ? val.ToUpper() : val.ToLower();
}
public static String ruleCombintIt(String val1, String val2)
{
return val1 + val2;
}
}
This appears to satisfy all of your key requirements:
1) Need to be able to get the String return value
Satisfied by the Func<string>
2) Need to be able to set the actual parameter values of the function at the time I add the item to the list.
I'm glad you said set the parameter values - and not the parameter types. This would be much harder to accomplish as you cant store, for example, a Func<string,string,string> and a Func<string, bool, string> in the same collection easily.
3) Need to be able to handle cases (as shown) where each method being added to the list may have different parameters.
This is no problem as demonstrated so long as 2) above holds true.
From Parameter to Property?
public class ConcatenateListTMember
{
public static void Test()
{
var someList = new List<AnyClass>();
someList.Add(new AnyClass("value1"));
someList.Add(new AnyClass("value2"));
Console.WriteLine(Concatenate(someList, "SomeProperty"));
Console.ReadLine();
}
static string Concatenate<T>(List<T> list, string specifiedPropertyOfT)
{
string output = String.Empty;
// TODO: Somehow concatenate all the specified property elements in the list?
return output;
}
}
internal class AnyClass
{
public AnyClass(string someProperty)
{
SomeProperty = someProperty;
}
public string SomeProperty { get; set; }
}
How might it be possible to implement the generic method in this code sample?
Please note that specifiedPropertyOfT does not have to be a string if the same aim can be achieved using another type.
Ideally, reflection would not be needed :)
I think you're looking for the new overloads of string.Join in .NET 4 which would allow:
IEnumerable<AnyClass> sequence = ...;
string joined = string.Join(",", sequence.Select(x => x.SomeProperty));
If you can't use a lambda expression to express the property - e.g. because this has to be done at execution time - then you will have to use reflection.
Note that the selector in Select doesn't have to return strings - String.Join will call ToString on any non-string values.
Even better - an extension method:
static string Concatenate<T>(this IEnumerable<T> list, Func<T,string> func)
{
return String.Join("",list.Select(func));
}
Usage:
someList.Concatenate(i => i.SomeProperty);
Live example: http://rextester.com/runcode?code=LRA78268
Try something like this. I've created an extension method on IEnumerable:
public static class Extension
{
public static string ConcatinateString<T>(this IEnumerable<T> collection, Func<T, string> GetValue)
{
StringBuilder sb = new StringBuilder();
foreach (var item in collection)
{
sb.Append(GetValue(item));
}
return sb.ToString();
}
}
Then so call it, you would use something like this:
var values = new List<TestClass>
{
new TestClass(){Name="John",Comment="Hello"},
new TestClass(){Name="Smith", Comment="Word"}
};
string s = values.ConcatinateString((x => x.Name));
string v = values.ConcatinateString((x => x.Comment));
In this example s = "JohnSmith" and v = "HelloWord". The Func() gives you flexibility. You are basically telling the function where to go to get the string to concatenate. I also used a StringBuilder in case you are working with long collections.
My first (and really horrible post) is below.
I try to do a complete example what I want to get. I hope this will be left explained a bit better.
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Boy> boys = new List<Boy>();
boys.Add(new Boy("Jhon", 7));
boys.Add(new Boy("Oscar", 6));
boys.Add(new Boy("Oscar", 7));
boys.Add(new Boy("Peter", 5));
ClassRoom myClass = new ClassRoom(boys);
Console.WriteLine(myClass.ByName("Oscar").Count); // Prints 2
Console.WriteLine(myClass.ByYearsOld(7).Count); // Prints 2
// This has errors...................
// But this is as I would like to call my BySomeConditions method....
Console.WriteLine( // It should print 1
myClass.BySomeConditions([myClass.ByName("Oscar"),
myClass.ByYearsOld(7)]
)
);
Console.ReadKey();
}
class ClassRoom
{
private List<Boy> students;
public ClassRoom(List<Boy> students)
{
this.students = students;
}
public List<Boy> ByName(string name)
{
return students.FindAll(x => x.Name == name);
}
public List<Boy> ByYearsOld(int yearsOld)
{
return students.FindAll(x => x.YearsOld == yearsOld);
}
// This has ERRORS.......................
public List<Boy> BySomeConditions(params Func<X, List<Boy>>[] conditions)
{
IEnumerable<Boy> result = students;
foreach (var condition in conditions) {
// I want it ONLY be called with existent functions (ByName and/or ByYearsOld)
result = result.Intersect(condition(this));
}
}
}
class Boy
{
public string Name { get; set; }
public int YearsOld { get; set; }
public Boy(string name, int yearsOld)
{
Name = name;
YearsOld = yearsOld;
}
}
}
}
============== first post =====================
Hello,
I have a class with methods:
public class X
{
private readonly List<string> myList;
public X(List<string> paramList) // string is really an object
{
myList = paramList;
}
// Now I want this...
public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
{
var result = myList;
foreach (Func<T, List<string>> condition in conditions)
{
result = result.Intersect(condition(T));
}
}
public List<string> check1(string S)
{
return myList.FindAll(x => x.FieldS == S);
}
public List<string> check1(int I)
{
return myList.FindAll(x => x.FieldI == I);
}
}
Sorry if there is some error, I have written from scrach to avoid complex real case.
What I want is call my methods like this:
X.check1("Jhon");
or
X.check2(12);
or (this is the goal of my question):
X.CheckConditions(X.check1("Jhon"), X.chek2(12));
Thanks and sorry by my poor example...
It is unclear where your T comes from.
Does this meet your requirements?
public class X<T>
{
private List<T> myList;
public List<T> CheckConditions(params Func<T, bool>[] conditions)
{
IEnumerable<T> query = myList;
foreach (Func<T, bool> condition in conditions)
{
query = query.Where(condition);
}
return query.ToList();
}
}
Then later:
List<T> result = X.CheckConditions(
z => z.FieldS == "Jhon",
z => z.FieldI == 12
);
You need to change the method signature of CheckConditions, it's accepting a variable number of List<string>, not functions.
public List<string> CheckConditions(params List<string>[] lists)
The return type of check1 is List<string>, so that needs to be the type of the parameter that CheckConditions accepts.
There's no reason to make it generic, you know that you want to operate on the current instance of X (so pass in this, instead of the T type parameter). You need to cleanup a few things to to get it to compile (return result and make the type of result and the Intersect call compatible). You can define it like this:
public List<string> CheckConditions(params Func<X, List<string>>[] conditions)
{
IEnumerable<string> result = myList;
foreach (var condition in conditions)
{
result = result.Intersect(condition(this));
}
return result.ToList();
}
Ant then call it like this:
xInstance.CheckConditions(x => x.check1("JHon"), x => x.check1(12));
All that said, I'm not sure why you wouldn't just pass around the results of these functions, instead of passing the actual functions around:
public List<string> CheckConditions(params List<string>[] conditions)
{
IEnumerable<string> result = myList;
foreach (var condition in conditions)
{
result = result.Intersect(condition);
}
return result.ToList();
}
Then call it as in your example, rather than passing in lambda expressions.
you could rewrite you function to look like this:
// Now I want this...
public List<string> CheckConditions(params Func<T, List<string>>[] conditions)
{
var result = myList;
foreach (Func<T, List<string>> condition in conditions)
{
result = result.Intersect(condition(T));
}
}
your call would then be X.CheckConditions(()=>X.check1("Jhon"), ()=>X.chek2(12));
and you need to provide an instance for x (since the methods are instance methods and not static methods)
In your example you pass T as an argument to the functor but T is a type argument som it can't be passed as an argument to the method. Did you mean to pass a value?
This begs for a clarification of why you would want to do this. Maybe if you provided details on what you are trying to accomplish (as opposed to how) then you could get a better solution to your problem.
What you pass to your
X.CheckConditions
is not a reference to the functions, but the returned value of their invocation.
Now, if you pass function reference - it does not come with parameters, unless you construct and pass a data-structure that will contain the function reference and the arguments it should work on.
In this case - generics is not the solution. You should consider another pattern to follow, like command pattern or strategy pattern, where you pass to your CheckConstruction instances of checker-objects, each is instantiated with the parameters it should work on, and either implements or is provided by the validation function.
Below function working ok but I want to make it simple.
if (list.Exists(delegate(string s) { return s.Contains(str); }))
{
string name = list.Find(delegate(string s) { return s.Contains(str); });
}
I am using delegate(string s) { return s.Contains(str); }
two times Is there any way to make this simple.
I know how to create delegate but don't know how to use it.
//create delegate
public delegate bool nameExistsDelegate(List<string> list, string name);
// Create a method for a delegate.
public static bool IsnameExists(List<string> list, string name)
{
return list.Exists(delegate(string s) { return s.Contains(name) ; });
}
// Create a method for a delegate.
public static string GetName(List<string> list, string name)
{
return list.Find(delegate(string s) { return s.Contains(name) ; });
}
UPDATE
stuck with .NET 2.0 so I can't use LINQ
The anonymous method you're using will be converted to a Predicate<string> delegate by the compiler. With this in mind, you can introduce a local to get rid of the redundancy you don't want.
Predicate<string> containsStr = delegate(string s) { return s.Contains(str); };
if (list.Exists(containsStr))
{
string name = list.Find(containsStr);
...
}
In C# 3.0 or later, you can express this even more succintly with lambda-expressions.
Predicate<string> containsStr = s => s.Contains(str);
On another note, you don't need to first test that str exists and then proceed to find it (assuming the list doesn't contain nulls), you could just do:
string name = list.Find(s => s.Contains(str));
if(name != null)
{
//found
}
Of course, I should also point out that strings don't contain any extra meta-data other than the characters present in them, so you don't gain anything by 'finding' a string in a list over just proving it exists (unless you meantFindIndex).
if you're on .net 3.5 you can use lamdas
//create delegate
public delegate bool nameExistsDelegate(List<string> list, string name);
static Func<string, bool> exists = s => return s.Contains(name);
// Create a method for a delegate.
public static bool IsnameExists(List<string> list, string name)
{
return list.Exists(s => exists(s));
}
// Create a method for a delegate.
public static string GetName(List<string> list, string name)
{
return list.Find(s => exists(s));
}
I'd recommend reading up on the standard delegate types in C#
Here you actually need a Predicate, which takes in an object, tests it with some condition and returns a pass/fail result.
Predicate<string> containsCheck = item = > item.Contains(str);
if (list.Exists(containsCheck)
{
string name = list.Find(containsCheck);
}
Note: all of the code can also be done using LINQ, which is considerable simpler. But I guess you must be learning delegates right now.. JFYI
using System.Linq;
...
Predicate<string> substringCheck = item => item.Contains(str);
var exists = list.Any(substringCheck);
var getMatch = list.First(substringCheck);
In the ContainsIngredients method in the following code, is it possible to cache the p.Ingredients value instead of explicitly referencing it several times? This is a fairly trivial example that I just cooked up for illustrative purposes, but the code I'm working on references values deep inside p eg. p.InnerObject.ExpensiveMethod().Value
edit:
I'm using the PredicateBuilder from http://www.albahari.com/nutshell/predicatebuilder.html
public class IngredientBag
{
private readonly Dictionary<string, string> _ingredients = new Dictionary<string, string>();
public void Add(string type, string name)
{
_ingredients.Add(type, name);
}
public string Get(string type)
{
return _ingredients[type];
}
public bool Contains(string type)
{
return _ingredients.ContainsKey(type);
}
}
public class Potion
{
public IngredientBag Ingredients { get; private set;}
public string Name {get; private set;}
public Potion(string name) : this(name, null)
{
}
public Potion(string name, IngredientBag ingredients)
{
Name = name;
Ingredients = ingredients;
}
public static Expression<Func<Potion, bool>>
ContainsIngredients(string ingredientType, params string[] ingredients)
{
var predicate = PredicateBuilder.False<Potion>();
// Here, I'm accessing p.Ingredients several times in one
// expression. Is there any way to cache this value and
// reference the cached value in the expression?
foreach (var ingredient in ingredients)
{
var temp = ingredient;
predicate = predicate.Or (
p => p.Ingredients != null &&
p.Ingredients.Contains(ingredientType) &&
p.Ingredients.Get(ingredientType).Contains(temp));
}
return predicate;
}
}
[STAThread]
static void Main()
{
var potions = new List<Potion>
{
new Potion("Invisibility", new IngredientBag()),
new Potion("Bonus"),
new Potion("Speed", new IngredientBag()),
new Potion("Strength", new IngredientBag()),
new Potion("Dummy Potion")
};
potions[0].Ingredients.Add("solid", "Eye of Newt");
potions[0].Ingredients.Add("liquid", "Gall of Peacock");
potions[0].Ingredients.Add("gas", "Breath of Spider");
potions[2].Ingredients.Add("solid", "Hair of Toad");
potions[2].Ingredients.Add("gas", "Peacock's anguish");
potions[3].Ingredients.Add("liquid", "Peacock Sweat");
potions[3].Ingredients.Add("gas", "Newt's aura");
var predicate = Potion.ContainsIngredients("solid", "Newt", "Toad")
.Or(Potion.ContainsIngredients("gas", "Spider", "Scorpion"));
foreach (var result in
from p in potions
where(predicate).Compile()(p)
select p)
{
Console.WriteLine(result.Name);
}
}
Have you considered Memoization?
The basic idea is this; if you have an expensive function call, there is a function which will calculate the expensive value on first call, but return a cached version thereafter. The function looks like this;
static Func<T> Remember<T>(Func<T> GetExpensiveValue)
{
bool isCached= false;
T cachedResult = default(T);
return () =>
{
if (!isCached)
{
cachedResult = GetExpensiveValue();
isCached = true;
}
return cachedResult;
};
}
This means you can write this;
// here's something that takes ages to calculate
Func<string> MyExpensiveMethod = () =>
{
System.Threading.Thread.Sleep(5000);
return "that took ages!";
};
// and heres a function call that only calculates it the once.
Func<string> CachedMethod = Remember(() => MyExpensiveMethod());
// only the first line takes five seconds;
// the second and third calls are instant.
Console.WriteLine(CachedMethod());
Console.WriteLine(CachedMethod());
Console.WriteLine(CachedMethod());
As a general strategy, it might help.
Can't you simply write your boolean expression in a separate static function which you call from your lambda - passing p.Ingredients as a parameter...
private static bool IsIngredientPresent(IngredientBag i, string ingredientType, string ingredient)
{
return i != null && i.Contains(ingredientType) && i.Get(ingredientType).Contains(ingredient);
}
public static Expression<Func<Potion, bool>>
ContainsIngredients(string ingredientType, params string[] ingredients)
{
var predicate = PredicateBuilder.False<Potion>();
// Here, I'm accessing p.Ingredients several times in one
// expression. Is there any way to cache this value and
// reference the cached value in the expression?
foreach (var ingredient in ingredients)
{
var temp = ingredient;
predicate = predicate.Or(
p => IsIngredientPresent(p.Ingredients, ingredientType, temp));
}
return predicate;
}
Well, in this case, if you can't use Memoization, you're rather restricted since you can really only use the stack as your cache: You've got no way to declare a new variable at the scope you'll need. All I can think of (and I'm not claiming it will be pretty) that will do what you want but retain the composability you need would be something like...
private static bool TestWith<T>(T cached, Func<T, bool> predicate)
{
return predicate(cached);
}
public static Expression<Func<Potion, bool>>
ContainsIngredients(string ingredientType, params string[] ingredients)
{
var predicate = PredicateBuilder.False<Potion>();
// Here, I'm accessing p.Ingredients several times in one
// expression. Is there any way to cache this value and
// reference the cached value in the expression?
foreach (var ingredient in ingredients)
{
var temp = ingredient;
predicate = predicate.Or (
p => TestWith(p.Ingredients,
i => i != null &&
i.Contains(ingredientType) &&
i.Get(ingredientType).Contains(temp));
}
return predicate;
}
You could combine together the results from multiple TestWith calls into a more complex boolean expression where required - caching the appropriate expensive value with each call - or you can nest them within the lambdas passed as the second parameter to deal with your complex deep hierarchies.
It would be quite hard to read code though and since you might be introducing a bunch more stack transitions with all the TestWith calls, whether it improves performance would depend on just how expensive your ExpensiveCall() was.
As a note, there won't be any inlining in the original example as suggested by another answer since the expression compiler doesn't do that level of optimisation as far as I know.
I would say no in this case. I assume that the compiler can figure out that it uses the p.Ingredients variable 3 times and will keep the variable closeby on the stack or the registers or whatever it uses.
Turbulent Intellect has the exactly right answer.
I just want to advise that you can strip some of the nulls and exceptions out of the types you are using to make it friendlier to use them.
public class IngredientBag
{
private Dictionary<string, string> _ingredients =
new Dictionary<string, string>();
public void Add(string type, string name)
{
_ingredients[type] = name;
}
public string Get(string type)
{
return _ingredients.ContainsKey(type) ? _ingredients[type] : null;
}
public bool Has(string type, string name)
{
return name == null ? false : this.Get(type) == name;
}
}
public Potion(string name) : this(name, new IngredientBag()) { }
Then, if you have the query parameters in this structure...
Dictionary<string, List<string>> ingredients;
You can write the query like this.
from p in Potions
where ingredients.Any(i => i.Value.Any(v => p.IngredientBag.Has(i.Key, v))
select p;
PS, why readonly?