Creating a Custom Predicate - c#

I am new to Lambda's and Delegates. I think my question may not be a good question but i am trying to write a simple Custom Predicate that act just like a Built-In Prediciate.
So i am going to share my Code: Please share with me that where i am going to make a mistake:
Built-In Predicate Code Example:
namespace Built_In_Predicate
{
class Program
{
static void Main(string[] args)
{
List<string> _ListOfPlayers = new List<string>()
{
"James Anderson",
"Broad",
"foo"
};
// Method 1. Predicate and Anonymous function.
Predicate<string> _Predicate = delegate (string someString) { return someString.Length == 3; };
string result = _ListOfPlayers.Find(_Predicate);
Console.WriteLine("Result : {0}", result);
}
}
}
Trying to Create a Custom Predicate (Code):
namespace CustomPredicate
{
class Program
{
// Delegate (Takes some string as a Input and return a Boolean.)
public delegate bool CustomPredicate(string someString);
static void Main(string[] args)
{
List<string> _ListOfPlayers = new List<string>()
{
"James Anderson",
"Broad",
"foo"
};
// Instance of CustomPredicate.
CustomPredicate customPredicate = delegate (string someString) { return someString.Length == 3; };
string result = _ListOfPlayers.Find(customPredicate); // its error.
}
}
}
Help will be appreciated.

Delegates cannot be implicitly converted to each other even if they have the same signature.
Find expects a System.Predicate<T> so you have to give it a System.Predicate<T>.
You can write your own Find method if you want to use your own CustomPredicate.
There are also ways to use your customPredicate variable in the call to Find:
_ListOfPlayers.Find(new Predicate<string>(customPredicate));
_ListOfPlayers.Find(customPredicate.Invoke);

You cannot call Find with something else as the type Predicate. But if you want your own delegate, you could call FirstOrDefault (System.Linq) and then use it.
private delegate bool CustomPredicate (string t);
static void Main(string[] args)
{
List<string> _ListOfPlayers = new List<string>()
{
"James Anderson",
"Broad",
"foo"
};
// Method 1. Predicate and Anonymous function.
CustomPredicate _Predicate = delegate (string someString) { return someString.Length == 3; };
string result = _ListOfPlayers.FirstOrDefault(x => _Predicate(x));
Console.WriteLine("Result : {0}", result);
Console.ReadLine();
}

Related

C# expand array to be arguments

void foo(int one, int two) {
}
public static void Main(string[] args) {
var bar = new int[] { 1, 2 };
foo(params bar);
}
What's the correct syntax to deconstruct the bar array and pass it as the arguments to the foo method?
In some other languages you can use a splat operator foo(...bar) or an unpack operator foo(*bar).
How can I do it in C#?
There isn't an equivalent function in C#. Each argument has to be passed individually.
There are, of course, work arounds that you likely already know. You could declare an overload for your function that would accept an array and call the original function using the first two inputs. The other alternative that I can think of is to declare the function parameter with the params keyword so that it could receive an array or multiple conma-separated elements when called.
void foo(params int[] numbers)
{ // TODO: Validate numbers length
int one = numbers[0];
int two = numbers[1];
}
public static void Main(string[] args) {
var bar = new int[] { 1, 2 };
// both valid function calls below
foo(bar);
foo(bar[0], bar[1]);
}
You can always use Reflection for such purpose.
Here is example snippet on your example method:
class MainClass
{
void foo(int one, int two)
{
Console.WriteLine(one + two);
}
static void Main()
{
var myInstance = new MainClass();
var bar = new object[] { 1, 2 };
var method = myInstance.GetType().GetMethod(nameof(MainClass.foo), BindingFlags.NonPublic | BindingFlags.Instance)
?? throw new InvalidOperationException($"Method '{nameof(MainClass.foo)}' not found");
method.Invoke(myInstance, bar) ;
}
}

Custom where can't run

class Program
{
private delegate Boolean SomeDelegate(string value);
static void Main(string[] args)
{
var data = new List<string>() { "bill", "david", "john", "daviddd" };
SomeDelegate AA = A;
var test2 = data.DoWhere(AA); //This Line Compile is wrong
}
public static bool A(string value)
{
if (value.StartsWith("d"))
{
return true;
}
return false;
}
}
public static class CustomClass
{
public static IEnumerable<T> DoWhere<T>(this IEnumerable<T> source, Func<T, Boolean> predicate)
{
foreach (T item in source)
{
if (predicate.Invoke(item))
{
yield return item;
}
}
}
}
I want to custom method and condition what data I need. But this code Compile is wrong in var test2 = data.DoWhere(AA);
cannot convert from 'SomeDelegate' to 'System.Func<string, bool>'
And I don't know How to fix it. Please review my code.
SomeDelegate(AA) is not Func<string, bool>. It should simply be a DoWhere(A) in your code. ie:
class Program
{
static void Main(string[] args)
{
var data = new List<string>() { "bill", "david", "john", "daviddd" };
var test2 = data.DoWhere(A); //This Line Compile is wrong
}
public static bool A(string value)
{
if (value.StartsWith("d"))
{
return true;
}
return false;
}
}
A simpler way to write it:
class Program
{
static void Main(string[] args)
{
var data = new List<string>() { "bill", "david", "john", "daviddd" };
Func<string, bool> A = value => value.StartsWith("d");
var test2 = data.DoWhere(A);
}
}
Note: Such a function should check if the value is null.
You can't cast an instance of SomeDelegate to a Func<string, bool>:
var test2 = data.DoWhere(AA); //This Line Compile is wrong
Try this instead:
var test2 = data.DoWhere(c => AA(c));
Or use Invoke:
var test2 = data.DoWhere(AA.Invoke);
Or use a method with same signature like A:
var test2 = data.DoWhere(A);
you said in a comment
I just want to custom my own condition method
so code can be much easier of the one you wrote:
public class Program
{
public static void Main(string[] args)
{
var data = new List<string>() { "bill", "david", "john", "daviddd" };
var stringsStartingWithD = data.Where (s => StarstWithD(s)).ToList();
var anotherOne = data.Where (s => SomeOtherTest(s)).ToList();
}
public static bool StarstWithD(string str)
{
if (str.StartsWith("d"))
{
return true;
}
return false;
}
public static bool SomeOtherTest(string str)
{
bool result = false;
// apply desired logic and return true/false
//...
return result;
}
}
For a simple test as the one you are using, you can also avoid creating the StartsWithDmethod and simply use something like this:
public class Program
{
public static void Main(string[] args)
{
var data = new List<string>() { "bill", "david", "john", "daviddd" };
var stringsStartingWithD = data.Where (s => s.StartsWith("d")).ToList();
}
Your entire code is just two lines now

pass lambda expression as callback to an extension method and pass parameter to it

I am trying to understand the concept of lambda expression,extension method,Linq and IEnumerable interface. You can guess that i am farely new to c sharp.Here i've come up with a problem which will incorporate all the above mentioned concepts . Here i have a list which contain three object.I want to change the name property of a Students object in a specified index .I wrote an extension method which accept a callback function.Callback function accepts an integer index and a new Name string. It should change the name property and return the object .But my code failed to do so as i am not sure how to pass parameter to Func callback in extension method.I am in need of some assistant to understand the problem and fix errors from my code ?
class Program
{
static void Main(string[] args)
{
List<Students> students = new List<Students>();
students.Add(new Students(111443, "sakib"));
students.Add(new Students(111445, "zami"));
students.Add(new Students(111444, "habib"));
var student = students.First();
var changed1 = students.Change((int num,string newname) => { return students[num].s_name = newname;});
}
}
public class Students
{
public int s_id;
public string s_name;
public Students(int id, string name)
{
this.s_id = id;
this.s_name = name;
}
}
public static class LinqHelper
{
public static IEnumerable<T> Change<T> (this IEnumerable<T> source, Func<int,string,T> callback)
{
var myList = new List<Students>();
myList.Add(callback(1,"zami")); // i was passing parameter here which is not so helpful i guess !
return myList;
}
}
The Func < int, string, T > denotes a function that accepts an integer and string as inputs and T as the return type. The anonymous function you have used has a return type of "string":
var changed1 = students.Change((int num,string newname) => { return students[num].s_name = newname;});
You should return the student instance from the function to make it work. Try replacing the above code with the following:
var changed1 = students.Change((int index, string newname) =>
{
var studentObj = students[index];
studentObj.s_name = newname;
return studentObj;
});
To allow the LinqHelper to accept the index and argument, use the following:
public static class LinqHelper
{
public static IEnumerable<T> Change<T>(this IEnumerable<T> source, Func<int, string, T> callback, int index, string argument)
{
var myList = new List<T>();
myList.Add(callback(index, argument)); // i was passing parameter here which is not so helpful i guess !
return myList;
}
}
And then, you could invoke the method as follows:
var changed1 = students.Change((int index, string newname) =>
{
var studentObj = students[index];
studentObj.s_name = newname;
return studentObj;
},
1,
"zami");
You haven't created the lambda that evaluated to Func<int, string, T>. Your call to Change extension should look like:
var changed1 = students.Change((num, newnam) => {
students[num].s_name = newnam;
return students[num];
});
(you should return T as Func requires).

C# Function as parameter

I need help. I'm making a programm and i have a problem.
I have a constructor with delegate already:
public delegate bool delIsDone(int curState, int needState);
public Progress(delIsDone doneFunction) { ... }
I need to pass it without creating it outside of creation:
public bool check() { return true }
Progress p = new Progress(check);
I need to do something like this:
Progress p = new ProgressChecker(bool check(int currentProgress, int needProgress) {
return currentProgress < needProgress;
});
Where ProgressChecker is a class that have method that check progress.
In loop i execute this function to get result. If function return "true" it's mean that "Achievement geted" and i need to hold it.
Thx for help
In the constructor you can pass in a function like so:
ProgressChecker(Func<int,int,bool> checker)
That means you can pass a function into the constructor for ProgressChecker
public bool checker (int a, int b)
{
return a < b;
}
var t = new ProgressChecker(checker);
EDIT:
If you want to use the delegate, then in the ProgressChecker class, the constructor must take in that delegate type:
private delIsDone delIsDone;
public ProgressChecker(delIsDone delIsDone)
{
this.delIsDone = delIsDone;
}
You can the pass a delegate instance like so:
public class Program
{
public delegate bool delIsDone(int curState, int needState);
public static bool checkNumbers(int a, int b)
{
return a < b;
}
public static void Main(string[] args)
{
var t = new ProgressChecker(new delIsDone(checkNumbers));
// OR var t = new ProgressChecker(new delIsDone((a, b) => { return a < b; }));
}
}
You can also create Expression Trees, it is my snippet for it (it can be easly converted to your example)
//easy way
Expression<Action<int>> printExpr = (arg) => Console.WriteLine(arg);
printExpr.Compile()(10);
//hard way
ParameterExpression param = Expression.Parameter(typeof(int), "arg");
MethodCallExpression methodCall = Expression.Call
(
typeof(Console).GetMethod("WriteLine", new[]
{
typeof(int)
}
),
param
);
Expression.Lambda<Action<int>>(methodCall, param).Compile()(10); //execution
More information ca be gathered at Generating Dynamic Methods with Expression Trees

"dynamic" for anonymous delegates?

I wonder if there is a possibility to make the "dynamic" type for variables work for anonymous delegates.
I've tried the following:
dynamic v = delegate() {
};
But then I got the following error message:
Cannot convert anonymous method to type 'dynamic' because it is not a delegate type
Unfortunately, also the following code doesn't work:
Delegate v = delegate() {
};
object v2 = delegate() {
};
What can I do if I want to make a Method that accepts any type of Delegate, even inline declared ones?
For example:
class X{
public void Y(dynamic d){
}
static void Main(){
Y(delegate(){});
Y(delegate(string x){});
}
}
This works, but it looks a little odd. You can give it any delegate, it will run it and also return a value.
You also need to specify the anonymous method signature at some point in order for the compiler to make any sense of it, hence the need to specify Action<T> or Func<T> or whatever.
Why can't an anonymous method be assigned to var?
static void Main(string[] args)
{
Action d = () => Console.WriteLine("Hi");
Execute(d); // Prints "Hi"
Action<string> d2 = (s) => Console.WriteLine(s);
Execute(d2, "Lo"); // Prints "Lo"
Func<string, string> d3 = (s) =>
{
Console.WriteLine(s);
return "Done";
};
var result = (string)Execute(d3, "Spaghettio"); // Prints "Spaghettio"
Console.WriteLine(result); // Prints "Done"
Console.Read();
}
static object Execute(Delegate d, params object[] args)
{
return d.DynamicInvoke(args);
}
If you declare a type for each of your delegates, it works.
// Declare it somewhere
delegate void DelegateType(string s);
// The cast is required to make the code compile
Test((DelegateType)((string s) => { MessageBox.Show(s); }));
public static void Test(dynamic dynDelegate)
{
dynDelegate("hello");
}
Action _;
dynamic test = (_ = () => Console.WriteLine("Test"));
test() // Test

Categories

Resources