Is it possible to cache a value evaluated in a lambda expression? - c#

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?

Related

How to check if an value matches all conditions

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);

C# - Pattern for iterating over predicates

I made a pattern which i dont really like.
It is as the following:
List<Element> listOfPossibleResults = getAllPossibleResults();
Element result = findResult(getFirstPriorityElements(listOfPossibleResults));
if (result!= null)
{
return result;
}
result = findResult(getSecondPriorityElements(listOfPossibleResults));
if (result!= null)
{
return result;
}
private Element findResult(List<Element> elements) {...};
private List<Element> getFirstPriorityElements(List<Element> elements) {...};
private List<Element> getSecondPriorityElements(List<Element> elements) {...};
etc..
Basically i'am creating sublists based on a couple of rules. After creating the sublist, i try and find a specific element in it. If i dont find, i move on to the next priority, and so on.
I would like a solution where i can iterate over these criterias, until i find a solution. But i dont know how to get them to a format which i can iterate over.
Can you guys give me a C# specific solution of the issue?
As #Lepijohnny mentioned, you can use Chain of responsibility design pattern. For example:
abstract class Handler<TRequest, TResult>
{
protected Handler<TRequest, TResult> successor;
public void SetSuccessor(Handler<TRequest, TResult> successor)
{
this.successor = successor;
}
public abstract TResult HandleRequest(TRequest request);
}
class FirstHandler : Handler<List<Element>, Element>
{
public override void HandleRequest(TRequest request)
{
Element result = findResult(getFirstPriorityElements(request));
if (result == null)
{
result = sucessor?.HandleRequest(request);
}
return result;
}
private Element findResult(List<Element> elements) {...};
private List<Element> getFirstPriorityElements(List<Element> elements) {...};
}
class SecondHandler : Handler<List<Element>, Element>
{
public override void HandleRequest(TRequest request)
{
Element result = findResult(getSecondPriorityElements(request));
if (result == null)
{
result = sucessor?.HandleRequest(request);
}
return result;
}
private Element findResult(List<Element> elements) {...};
private List<Element> getSecondPriorityElements(List<Element> elements) {...};
}
Usage:
void Example()
{
// Setup Chain of Responsibility
var h1 = new FirstHandler();
var h2 = new SecondHandler();
h1.SetSuccessor(h2);
var result = h1.Handle(new List<Element>());
}
It's a just quick example. I think it describe how this pattern works and you will be able to adjust it for your needs.
In the "result" class put a property called "Priority (int)" then:
result = listOfPossibleResults.GroupBy(x => x.Priority).OrderBy(x => x.Key);
then:
return result.FirstOrDefault(x => x.Count() > 0);
You will need to fill in the priority of the result items when you first retrieve them.
P.S. I typed the code right here, forgive me if there is a spelling mistake somewhere.
If you could refactor the methods getFirstPriorityElements(List<> list) to a single getPriorityElements(List<> list, int nr) you could do the following
method IteratePredicates(List<> list, int nr = 0)
{
if (nr>maxpriority) return null;
return findresult(getPriorityElements(list,nr)) ?? IteratePredicates(list,nr++);
}
In a for loop:
method IteratePredicates(List<> list, int nr = 0)
{
for (int i = 0; i < maxpriority; i++)
{
var result = findresult(getPriorityElements(list, nr));
if (result != null)
return result;
}
return null;
}
Am I right that your get__PriorityElements is literally a filter? In that case, it's more declarative and hopefully more readable to treat those like this:
Func<Element, bool> isFirstPriority = ...;
var firstPriorityElements = elements.Where(isFirstPriority);
And now your overall goal is to extract a single element (or none) from the highest-possible priority subsequence, using a predicate contained in findResult? So replace this with an actual predicate
Func<Element, bool> isResult = ...;
like so. Now you want to look through all the first priority elements for an isResult match, then if not found all the second priority elements, etc. This sounds just like a sequence concatenation! So we end up with
var prioritisedSequence = elements
.Where(isFirstPriority)
.Concat(elements
.Where(isSecondPriority))
.Concat....;
And finally the result
var result = prioritisedSequence
.FirstOrDefault(isResult);
Since Where and Concat are lazily enumerated this has the benefit that it is declarative while avoiding more work than necessary, and it's lightweight and 'LINQy' as well.
If you want abstract it even more, and anticipate changes in how priorities will be arranged, you could actually make a higher order list for those like this:
IEnumerable<Func<Element, bool>> priorityFilters = new[]
{
isFirstPriority,
isSecondPriority,
...
};
and then the concatenation can be performed as an aggregation over that sequence:
var prioritisedSequence = priorityFilters
.Aggregate(
Enumerable.Empty<Element>(),
(current, filter) => current.Concat(elements.Where(filter)));
This change may make it easier to add new priorities in future, or you may think it clutters and hides the intention of your code.
You can treat methods as objects using Func<T, T>, and then you can also put them in e.g. an array. Then you can iterate over the array, calling the methods one by one until a result is found.
The solution then becomes:
var methods = new Func<List<Element>, List<Element>>[]
{ getFirstPriorityElements, getSecondPriorityElements };
return methods
.Select(method => findResult(method(listOfPossibleResults)))
.Where(result => result != null)
.FirstOrDefault();
This is short and readable, works without changing your methods or types, and no need to add classes just for the sake of applying a pattern.
You can use the specs pattern Here is a sample code:
Create a interface with a criteria:
public interface ISpecification<T>
{
Expression<Func<T, bool>> Criteria { get; }
}
Then create a class that holds your query specs:
public class GlobalSongSpecification : ISpecification<Song>
{
public List<int> GenreIdsToInclude { get; set; } = new List<int>();
public List<int> AlbumIdsToInclude { get; set; } = new List<int>();
public List<string> ArtistsToInclude { get; set; } = new List<string>();
public string TitleFilter { get; set; }
public int MinRating { get; set; }
[JsonIgnore]
public Expression<Func<Song, bool>> Criteria
{
get
{
return s =>
(!GenreIdsToInclude.Any() || s.Genres.Any(g => GenreIdsToInclude.Any(gId => gId == g.Id))) &&
(!AlbumIdsToInclude.Any() || AlbumIdsToInclude.Contains(s.AlbumId)) &&
(!ArtistsToInclude.Any() ||ArtistsToInclude.Contains(s.Artist)) &&
(String.IsNullOrEmpty(this.TitleFilter) || s.Title.Contains(TitleFilter)) &&
s.Rating >= MinRating;
}
}
}
Create a repository with a method that exposes one that receives ISpecification:
public interface ISongRepository
{
IEnumerable<Song> List(ISpecification<Song> specification);
//IQueryable<Song> List();
Song GetById(int id);
void Add(Song song);
IEnumerable<string> AllArtists();
IEnumerable<Genre> AllGenres();
}
And your client code call the GlobalSongSpecification, populates it and pass it to the repository in order to filter by the criteria:
public ActionResult Index(List<int> selectedGenres = null,
List<string> selectedArtists = null,
string titleSearch = null,
int minRating = 0,
string filter = null,
string save = null,
string playlistName = null)
{
if (selectedArtists == null) { selectedArtists = new List<string>(); }
if (selectedGenres == null) { selectedGenres = new List<int>(); }
var spec = new GlobalSongSpecification();
spec.ArtistsToInclude.AddRange(selectedArtists);
spec.GenreIdsToInclude.AddRange(selectedGenres);
spec.MinRating = minRating;
spec.TitleFilter = titleSearch;
var songs = _songRepository.List(spec);
//You can work with the filtered data at this point
}
And you populate a razor view or expose it as web api.
The sample code is from pluralsight desing patterns library course Here(Specification Pattern module)

How to get arguments from an Expression where TDelegate is a callback

I'm attempting to write a simple generic cache but running into problems with generating unique enough keys with using System.Func as a callback.
What I ideally want is to be able to pass in an invocable delegate of some description so that the cache itself can get the value, and determine a key all from the same expression. Right now I'm getting exceptions because I'm not passing in an argument that implements or inherits from MethodCallExpression. What should I be using instead of a System.Func for this intended behaviour?
public class SimpleCacheKeyGenerator : ICacheKey
{
public string GetCacheKey<T>(Expression<Func<T>> action)
{
var body = (MethodCallExpression) action.Body; //!!! Exception Raised - action.Body is FieldExpression
ICollection<object> parameters = (from MemberExpression expression in body.Arguments
select
((FieldInfo) expression.Member).GetValue(
((ConstantExpression) expression.Expression).Value)).ToList();
var sb = new StringBuilder(100);
sb.Append(body.Type.Namespace);
sb.Append("-");
sb.Append(body.Method.Name);
parameters.ToList().ForEach(x =>
{
sb.Append("-");
sb.Append(x);
});
return sb.ToString();
}
}
public class InMemoryCache : ICacheService
{
private readonly ICachePolicy _cachePolicy;
private readonly ICacheKey _cacheKey;
public InMemoryCache(ICachePolicy cachePolicy, ICacheKey cacheKey)
{
_cachePolicy = cachePolicy;
_cacheKey = cacheKey;
}
public T Get<T>(Func<T> getItemCallback) where T : class
{
var cacheID = _cacheKey.GetCacheKey(() => getItemCallback);
var item = HttpRuntime.Cache.Get(cacheID) as T;
if (item == null)
{
item = getItemCallback();
if (_cachePolicy.RenewLeaseOnAccess)
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, System.Web.Caching.Cache.NoAbsoluteExpiration, _cachePolicy.ExpiresAfter);
}
else
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, DateTime.UtcNow + _cachePolicy.ExpiresAfter, System.Web.Caching.Cache.NoSlidingExpiration);
}
}
return item;
}
}
The problem is, you can't easily use both the Expression> and Func representing the same thing without duplicating the code.
You could possibly convert Expression> to a Func with LambdaExpression>.Compile() method, but that could create a performance problem, since Compile actually uses assembly emit, which is quite expensive.
Here is how i would implement the same thing without using Expressions and compilation.
You can find the same pattern everywhere in the standard Linq extensions.
Pass your argument as a separate object.
The type you use as an argument will be used for type inference for the delegate, and the argument itself will provide the arguments for the delegate at the same type.
Note that the cache in this implementation works because of the default ToString implementation of the anonimous objects used as arguments.
void Main()
{
var computeCount = 0;
var item1 = GetCached(new{x = 1, y = 2}, (arg)=>{computeCount++; return arg.x + arg.y;});
Console.WriteLine(item1);
var item2 = GetCached(new{x = 1, y = 2}, (arg)=>{computeCount++; return arg.x + arg.y;});
Console.WriteLine(item2);
var item3 = GetCached(new{x = 1, y = 3}, (arg)=>{computeCount++; return arg.x + arg.y;});
Console.WriteLine(item3);
Console.WriteLine("Compute count:");
Console.WriteLine(computeCount);
}
Dictionary<string, object> _cache = new Dictionary<string, object>();
E GetCached<T, E>(T arg, Func<T,E> getter)
{
// Creating the cache key.
// Assuming T implements ToString correctly for cache to work.
var cacheKey = arg.ToString();
object result;
if (!_cache.TryGetValue(cacheKey, out result))
{
var newItem = getter(arg);
_cache.Add(cacheKey, newItem);
return newItem;
}
else
{
Console.WriteLine("Cache hit: {0}", cacheKey);
}
return (E)result;
}
Console output:
3
Cache hit: { x = 1, y = 2 }
3
4
Compute count:
2
You get this exception because (() => getItemCallback) means (() => { return getItemCallback; })
That's why action.Body is not a method call, it is the return statement. If you change your code to (() => getItemCallback()) you should not have the error. But you won't have any arguments.
To obtain arguments of the base call, you will have to change your code to accept an Expression and Compile your lambda.
public T Get<T>(Expression<Func<T>> getItemCallbackExpression) where T : class
{
var cacheID = _cacheKey.GetCacheKey(getItemCallbackExpression);
var item = HttpRuntime.Cache.Get(cacheID) as T;
if (item == null)
{
item = getItemCallback.Compile()();
if (_cachePolicy.RenewLeaseOnAccess)
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, System.Web.Caching.Cache.NoAbsoluteExpiration, _cachePolicy.ExpiresAfter);
}
else
{
HttpContext.Current.Cache.Insert(cacheID, getItemCallback, null, DateTime.UtcNow + _cachePolicy.ExpiresAfter, System.Web.Caching.Cache.NoSlidingExpiration);
}
}
return item;
}
I won't recommend this approach because compiling an expression takes time.
It may be easier and more performant to manually generate cache keys. If you really want to automatically manage cache keys. You may have a look to Aspect Oriented Programmation using castle.Core or PostSharp. Theses tools will allow you to automatically add code to some of your methods and automatically add cache logic.
I modified the code as below, I got the expected result this way, so you can try this, I hope this would be helpful.
public class SimpleCacheKeyGenerator
{
public string GetCacheKey<T, TObject>(Expression<Func<T, TObject>> action)
{
var body = (MethodCallExpression) action.Body;
ICollection<object> parameters = body.Arguments.Select(x => ((ConstantExpression) x).Value).ToList();
var sb = new StringBuilder(100);
sb.Append(body.Type.Namespace);
sb.Append("-");
sb.Append(body.Method.Name);
parameters.ToList().ForEach(x =>
{
sb.Append("-");
sb.Append(x);
});
return sb.ToString();
}
}
public class InMemoryCache
{
public void Get<T, TObject>(Expression<Func<T, TObject>> getItemCallback)
{
var generator = new SimpleCacheKeyGenerator();
Console.WriteLine(generator.GetCacheKey(getItemCallback));
}
}
main:
private static void Main(string[] args)
{
var cache = new InMemoryCache();
var tt = new SomeContextImpl();
cache.Get<SomeContextImpl, string>(x => x.Any("hello", "hi"));
Console.ReadKey();
}
somcontextimpl:
public class SomeContextImpl
{
public string Any(string parameter1, string parameter2) { return ""; }
}

C# Passing an array of Func<T, List<myClass>> to a method

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.

Delegate as 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);

Categories

Resources