a list of dynamic functions and dynamically calling them - c#

I would like to be able to store various static methods in a List and later look them up and dynamically call them.
Each of the static methods has different numbers of args, types and return values
static int X(int,int)....
static string Y(int,int,string)
I'd like to have a List that I can add them all to:
List<dynamic> list
list.Add(X);
list.Add(Y);
and later:
dynamic result = list[0](1,2);
dynamic result2 = list[1](5,10,"hello")
How to do this in C# 4?

You can create a list of delegate-instances, using an appropriate delegate-type for each method.
var list = new List<dynamic>
{
new Func<int, int, int> (X),
new Func<int, int, string, string> (Y)
};
dynamic result = list[0](1, 2); // like X(1, 2)
dynamic result2 = list[1](5, 10, "hello") // like Y(5, 10, "hello")

You actually don't need the power of dynamic here, you can do with simple List<object>:
class Program
{
static int f(int x) { return x + 1; }
static void g(int x, int y) { Console.WriteLine("hallo"); }
static void Main(string[] args)
{
List<object> l = new List<object>();
l.Add((Func<int, int>)f);
l.Add((Action<int, int>)g);
int r = ((Func<int, int>)l[0])(5);
((Action<int, int>)l[1])(0, 0);
}
}
(well, you need a cast, but you need to somehow know the signature of each of the stored methods anyway)

List<dynamic> list = new List<dynamic>();
Action<int, int> myFunc = (int x, int y) => Console.WriteLine("{0}, {1}", x, y);
Action<int, int> myFunc2 = (int x, int y) => Console.WriteLine("{0}, {1}", x, y);
list.Add(myFunc);
list.Add(myFunc2);
(list[0])(5, 6);

Related

How to use ?? with lambda expression?

Can we simplify the following with ?? and lambda expression?
Func<int, int> func = f; // f is a function parameter
if (func == null) // if f passed by the user is null then we use the default identity function f(x)=x.
func = x => x;
I cannot do something Func<int, int> func = f ?? x=>x;. Could you?
Edit
My scenario is as follows.
class Program
{
static double Average(int[] data, Func<int, int> f = null)
{
int sum = 0;
Func<int, int> func = f ?? new Func<int, int>(x => x);
//Func<int, int> func = f;
//if (func == null)
// func = x => x;
foreach (int x in data)
sum += func(x);
return (double)sum / data.Length;
}
static void Main(string[] args)
{
int[] data = { 1, 2, 3 };
Console.WriteLine(Average(data));
}
}
The precedence of null-coalescing operator is higher than lambda declaration.
Func<int, int> func = f ?? (x => x);
Possible duplicate of Null-coalescing operator and lambda expression
This should work
Func<int, int> func = f ?? (x=>x);
Your statement is parsed as
Func<int, int> func = (f ?? x)=>x;
Please search through the available answers first to check if somebody has already answered it.

Join 2 lists have different length by in LINQ

How can I join 2 lists of different lengths. it should join with the sequence.
Eg.
{1,2,3,4} with {5,6,7}
I need to get result like below.
{{1,5}, {2,6}, {3,7}, {4,null}}
I tried this.
var qry = a.Select((i, index) => new {i, j = b[index]});
But its throwing error since the lists are having different lengths.
Please help me to get the solution.
This should work:
var a = new int?[] { 1, 2, 3, 4 };
var b = new int?[] { 5, 6, 7 };
var result = Enumerable.Range(0, Math.Max(a.Count(), b.Count()))
.Select(n => new[] {a.ElementAtOrDefault(n), b.ElementAtOrDefault(n)});
Do note the ? in the array declarations. That is necessary in order to have null values in the resulting list. Omitting the ? causes the result to have 0 instead of null.
If you can't or don't want to declare the arrays as int?, then you'll have to do the cast in the Select like so:
var result = Enumerable.Range(0, Math.Max(a.Count(), b.Count()))
.Select(n => new[] { a.Select(i => (int?)i).ElementAtOrDefault(n), b.Select(i => (int?)i).ElementAtOrDefault(n) });
This second bit of code will work correctly with regular int arrays or Lists.
The ugly but working version is the following:
a.Cast<int?>().Concat(Enumerable.Repeat<int?>(null, Math.Max(b.Count() - a.Count(), 0)))
.Zip(b.Cast<int?>()
.Concat(Enumerable.Repeat<int?>(null, Math.Max(a.Count() - b.Count(), 0))),
(x, y) => new { x, y });
Its drawback it double evaluation of a collection (the first one is by calling .Count()).
So it is better just to write an extension
static IEnumerable<TResult> ZipNull<T1, T2, TResult>(this IEnumerable<T1> a, IEnumerable<T2> b, Func<T1?, T2?, TResult> func)
where T1 : struct
where T2 : struct
{
using (var it1 = a.GetEnumerator())
using (var it2 = b.GetEnumerator())
{
while (true)
{
if (it1.MoveNext())
{
if (it2.MoveNext())
{
yield return func(it1.Current, it2.Current);
}
else
{
yield return func(it1.Current, null);
}
}
else
{
if (it2.MoveNext())
{
yield return func(null, it2.Current);
}
else
{
break;
}
}
}
}
}
and use it as
a.ZipNull(b, (x, y) => new { x, y });
What you have is effectively a Zip, but where it zips to the end of the longer, rather than the shorter, of the two sequences. You can write such a Zip method, with something that looks a bit similar to the actual Zip implementation:
public static IEnumerable<TResult> ZipAll<TSource, TSecond, TResult>(this IEnumerable<TSource> source,
IEnumerable<TSecond> other,
Func<TSource, TSecond, TResult> projection)
{
using (var firstIterator = source.GetEnumerator())
using (var secondIterator = other.GetEnumerator())
{
while (true)
{
bool hasFirst = firstIterator.MoveNext();
bool hasSecond = secondIterator.MoveNext();
TSource first = hasFirst ? firstIterator.Current : default(TSource);
TSecond second = hasSecond ? secondIterator.Current : default(TSecond);
if (hasFirst || hasSecond)
yield return projection(first, second);
else
yield break;
}
}
}
With that you can write:
a.ZipAll(b, (i, j) => new { i, j });
You could make the code a bit shorter by requiring the inputs to be lists, but the code wouldn't be any faster as lists, just less typing, and it's not like it's that much extra work to support any sequence, so I'd say it's worth the added few lines of code.
Simply loop through the lists and construct new, let's say Dictionary<int?, int?> out of each list element:
var theFirstList = new List<int?> { 1, 2, 3, 4 };
var theSecondList = new List<int?> { 5, 6, 7 };
var el = new Dictionary<int?, int?>();
var length = Math.Max(theFirstList.Count, theSecondList.Count);
for (int i = 0; i < length; i++)
{
el.Add(theFirstList.ElementAtOrDefault(i), theSecondList.ElementAtOrDefault(i));
}
var x = new[] { 1, 2, 3, 4 }.ToList();
var y = new[] { 5, 6, 7 }.ToList();
var arrayLists = new[] {x, y}.OrderBy(t => t.Count).ToList();
var result = arrayLists
.Last()
.Select((item, i) => new[] { x[i], i < arrayLists.First().Count ? y[i] : (int?)null })
.ToList();
this should work for any IEnumerable

Passing delegate object in the Where method

using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Where_MethodGroup
{
public delegate List<int> WhereDelegate(List<int> list);
class Program :IEnumerable
{
static void Main(string[] args)
{
List<int> list = new List<int>();
list.AddRange(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
WhereDelegate lessThanFive;
lessThanFive = GroupConversionMethod;
IEnumerable<int> query = list.Where(lessThanFive);
foreach (int i in query)
{
Console.WriteLine(i);
}
}
public static List<int> GroupConversionMethod(List<int> list1)
{
Console.WriteLine("Integers less than 5 are :");
foreach (int i in list1)
{
if (i < 5)
{
yield return i;
}
}
}
}
}
I have to Find all the elements less than five by passing a delegate object in the where method. While defining the delegate object use Method Group Conversion Syntax for call back function to be used (Define delegate object through new operator).
I am getting error in the line:
IEnumerable<int> query = list.Where(lessThanFive)
that where method has some invalid arguments, what could be the reasonable fix for this error?
The Where statment get as parameter Func<int,bool> in this case.
You need to write function that get int and return true or false
Try something like this:
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>();
list.AddRange(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
IEnumerable<int> query = list.Where(isInGroup);
foreach (int i in query)
{
Console.WriteLine(i);
}
}
public static bool isInGroup(int elem)
{
return elem < 5;
}
}
The problem is that you are trying to make a delegate which takes as parameter a list and returns a list of integers, while you are sending in linq Where method elemets one by one (so only one integer) and you are expecting to return a bool.
If you change the signature of the delegate to be like this, it will work:
public delegate bool WhereDelegate(int element);
Then you can call it in the following way:
static void Main(string[] args)
{
WhereDelegate del = (int element) => element < 5;
List<int> list = new List<int>();
list.AddRange(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
IEnumerable<int> query = list.Where(x => del(x));
}
using lambda operator =>
This is equivalent to writing a method and assigning it to the delegate:
public static bool Method(int i)
{
return i < 5;
}
then at the delegate instantiate:
WhereDelegate del = Method;
And if you want to use the new keyword as you specified (even if it is not necessary in this case), you can write:
WhereDelegate del = new WhereDelegate((int element) => element < 5);
or
WhereDelegate del = new WhereDelegate(Method);
When creating the delegate.
You can try the following:
IEnumerable<int> query = list.Where(c => c < 5);
or
IEnumerable<int> query = from e in list
where e < 5
select e;

Returning 2 arrays from a function

I create 2 jagged arrays inside my function:
double[][] x = new double[i][];
double[][] y = new double[j][];
I perform some sort of operations on them, and want to return both of them as a result of the function. How can I do that?
Well you could return an array of jagged arrays: double[][][]
public double[][][] GetData(int i, int j)
{
double[][] x = new double[i][];
double[][] y = new double[j][];
return new [] {x, y};
}
but it may make more sense to define a class to give the results context. If you return two arrays what do they mean? Are they always in the same order? By just returning an array you leave a lot for the consumer to learn about the meaning of the return type. A class, on the other hand, would provide context:
public TwoArrays GetData(int i, int j)
{
double[][] x = new double[i][];
double[][] y = new double[j][];
return new TwoArrays {X = x, Y = y};
}
public class TwoArrays
{
public double[][] X {get; set;}
public double[][] Y {get; set;}
}
Tuples are a completely valid option as well. Some folks don't like them as a matter of opinion, and they're NOT great options for public APIs, but they're useful without adding yet another class to your namespace. You can go overboard with them, and four- and five-tuples exceed even my tolerance for them
double[][] x = new double[i][];
double[][] y = new double[j][];
// Work your magic
return new Tuple<double[][], double[][]>(x, y);
Item1 and Item2 will now be your double[][] arrays.

How to store functions in Dictionary with uint as key (C#)

Can someone provide me an example of how maybe I store different functions in a dictionary with int as a key and function as value. So then I could easly call function as following:
functionsDictionary[123](string);
Note all functions in dictionary will take only one input which is string. And will have no return.
It sounds like you're after
Dictionary<int, Action<string>>
or possibly (based on your title)
Dictionary<uint, Action<string>>
Sample:
using System;
using System.Collections.Generic;
class Test
{
static void Main()
{
var dictionary = new Dictionary<int, Action<string>>
{
{ 5, x => Console.WriteLine("Action for 5: {0}", x) },
{ 13, x => Console.WriteLine("Unlucky for some: {0}", x) }
};
dictionary[5]("Woot");
dictionary[13]("Not really");
// You can add later easily too
dictionary.Add(10, x => Console.WriteLine("Ten {0}", x));
dictionary[15] = x => Console.WriteLine("Fifteen {0}", x);
// Method group conversions work too
dictionary.Add(0, MethodTakingString);
}
static void MethodTakingString(string x)
{
}
}
Dictionary<int, Action<string>> _functions = new Dictionary<int, Action<string>>();
_functions[123]("hello");

Categories

Resources