I have an object of any of the func types func<>, Func<,>, func<,,> ... And I'd like to replace one of the input parameters with a constant value.
eg:
object SetParameter<T>(object function, int index, T value){
//I don't know how to code this.
}
Func<int, String, String> function = (a, b) => a.ToString() + b;
object objectFunction = function;
object newFunction = SetParameter<int>(objectFunction, 0, 5);
// Here the new function should be a Func<String, String> which value "(b) => function(5, b)"
I already now how to get the type of the resulting function, but that does not really help me in implementing the desired behavior:
private Type GetNewFunctionType<T>(object originalFunction, int index, T value)
{
Type genericType = originalFunction.GetType();
if (genericType.IsGenericType)
{
var types = genericType.GetGenericArguments().ToList();
types.RemoveAt(index);
Type genericTypeDefinition = genericType.GetGenericTypeDefinition();
return genericTypeDefinition.MakeGenericType(types.ToArray());
}
throw new InvalidOperationException($"{nameof(originalFunction)} must be a generic type");
}
It's not quite clear what the purpose of your conversion is for, but wouldn't it be easier to avoid all the reflection. E.g.:
Func<int, string, string> func3 = (a, b) => a.ToString() + b;
Func<string, string> func3withConst = (b) => func3(10, b);
Since you are talking about a very limited scope (supporting just Func<TReturn>, Func<T1, TReturn> and Func<T1, T2, TReturn>) doing this through reflection is much more error prone and harder to read.
Just in case you need to use expression tree to build the function:
object SetParameter<T>(object function, int index, T value)
{
var parameterTypes = function.GetType().GetGenericArguments();
// Skip where i == index
var newFuncParameterTypes = parameterTypes.SkipWhile((_, i) => i == index).ToArray();
// Let's assume function is Fun<,,> to make this example simple :)
var newFuncType = typeof(Func<,>).MakeGenericType(newFuncParameterTypes);
// Now build a new function using expression tree.
var methodCallParameterTypes = parameterTypes.Reverse().Skip(1).Reverse().ToArray();
var methodCallParameters = methodCallParameterTypes.Select(
(t, i) => i == index
? (Expression)Expression.Constant(value, typeof(T))
: Expression.Parameter(t, "b")
).ToArray();
// func.Invoke(5, b)
var callFunction = Expression.Invoke(
Expression.Constant(function),
methodCallParameters);
// b => func.Invoke(5, b)
var newFunc = Expression.Lambda(
newFuncType,
callFunction,
methodCallParameters.OfType<ParameterExpression>()
).Compile();
return newFunc;
}
To use this:
Func<int, string, string> func = (a, b) => a.ToString() + b;
var newFunc = (Func<string, string>)SetParameter<int>(func, 0, 5);
// Output: 5b
Console.WriteLine(newFunc("b"));
Related
I do have a string of Empids separated by comma like:
EMpID:"2007,2008,2002,1992,1000,2108,1085
and I need to retrieve the records of all those specified employees using LINQ query.
I tried it with looping but I need to get that in efficient and faster way.
Here goes what i did using looping.
string[] EMpID_str = LeaveDictionary["EMpID"].ToString().Split(',');
for (int i = 0; i < EMpID_str.Length; i++)
{
EMpID = Convert.ToInt32(EMpID_str[i]);
//Linq to get data for each Empid goes here
}
But What I need is to use single LINQ or Lambda query to retrieve the same.Without looping
First convert your ,(comma) separated empId to string array like below:
var empArr = EmpId.split(',');
var employeesResult = emplyeeList.Where(x => empArr.contains(x.EmpId.ToString()));
I hope, it will help someone.
If the Ids that you want to fetch are numbers, not strings, then you should not convert the string to an array of strings, but to a sequence of numbers:
IEnumerable<int> employeeIdsToFetch = LeaveDictionary["EMpID"].ToString()
.Split(',')
.Select(splitText => Int32.Parse(splitText));
To fetch all employees with thees Ids:
var fetchedEmployees = dbContext.Employees
.Where(employee => employeeIdsToFetch.Contains(employee.Id))
.Select(employee => new
{
// Select only the employee properties that you plan to use:
Id = employee.Id,
Name = employee.Name,
...
});
You can use the Expression class to build a Func<int, bool> from your string and use it with the Where methode:
var str = "2,5,8,9,4,6,7";
var para = Expression.Parameter(typeof(int));
var body = str.Split(",")
.Select(s => int.Parse(s))
.Select(i => Expression.Constant(i))
.Select(c => Expression.Equal(para, c))
.Aggregate((a, b) => Expression.Or(a, b));
Func<int, bool> func = Expression.Lambda<Func<int, bool>>(body, para).Compile();
and if you this solution to work with linq to SQL just dont compile the expression at the end and let the linq to SQL engine compile it to an efficent SQL expression.
Instead of the Aggregate Method (which will produce an expression with linear complexity) one could use an divide and conquer approach to fold the values into one value.
For example with this class:
public static class Helper
{
public static T EfficientFold<T>(this List<T> list, Func<T, T, T> func)
{
return EfficientFold(list, 0, list.Count, func);
}
private static T EfficientFold<T>(List<T> list, int lowerbound, int upperbound, Func<T, T, T> func)
{
int diff = upperbound - lowerbound;
var mid = lowerbound + diff / 2;
if (diff < 1)
{
throw new Exception();
}
else if (diff == 1)
{
return list[lowerbound];
}
else
{
var left = EfficientFold(list, lowerbound, mid, func);
var right = EfficientFold(list, mid, upperbound, func);
return func(left, right);
}
}
}
and then we can do
var body = str.Split(",")
.Select(s => int.Parse(s))
.Select(i => Expression.Constant(i))
.Select(c => Expression.Equal(para, c))
.ToList()
.EfficientFold((a, b) => Expression.Or(a, b));
which gives the evaluation a complexity of log(n).
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.
how can I add an extra parameter to my Func<> expression ? Something like:
Func<char, bool> myPredicate = (x) => (char.IsLetter(x) || x == 'X');
...
"abc".All(x => char.IsDigit(x) || myPredicate);
but I get an error
Operator '||' cannot be applied to operands of type 'bool' and Func< char, bool>
You need to invoke the myPredicate function like this:
"abc".All(x => char.IsDigit(x) || myPredicate(x));
Or, what about this other approach?
var text = "abc";
var predicates = new Func<char, bool>[] {
x => char.IsLetter(x) || x == 'X',
char.IsDigit
};
var result = predicates.Any(text.All);
// Outputs TRUE
Console.WriteLine(result);
Also, if you need to check many specific characters, you can create a charEquals with curried parameters:
var text = "abc";
// More type inference to generalize charEquals to just equals, please!
Func<char, Func<char, bool>> charEquals = ca => cb => ca == cb;
var predicates = new Func<char, bool>[] {
char.IsLetter,
charEquals('X'),
charEquals('Y'),
charEquals('Z'),
char.IsDigit
};
var result = predicates.Any(text.All);
Console.WriteLine(result);
I have a list comparison function which is given below
public delegate bool CompareValue<in T1, in T2>(T1 val1, T2 val2);
public static bool CompareTwoLists<T1, T2>(IEnumerable<T1> list1, IEnumerable<T2> list2, CompareValue<T1, T2> compareValue)
{
return list1.Select(item1 => list2.Any(item2 => compareValue(item1, item2))).All(search => search)
&& list2.Select(item2 => list1.Any(item1 => compareValue(item1, item2))).All(search => search);
}
And this function is calling like below
bool IsSuccess1 = ListComparison.CompareTwoLists(listProduct, listProduct2, (listProductx, listProductx2) => listProductx.ProductName == listProductx2.ProductName);
Here delegate expression is static now. This is using to compare a particular column in two list items. How to create above code dynamically based on a list
List<CompareColumns> listCompareColumns = new List<Classes.CompareColumns>();
CompareColumns objDup1 = new CompareColumns();
objDup1.Columns = "ProductName";
CompareColumns objDup2 = new CompareColumns();
objDup2.Columns = "ProductCode";
listCompareColumns.Add(objDup1);
listCompareColumns.Add(objDup2);
Above list may have one or more columns. We need to compare these columns in the comparison lists. based on the above list how to generate below code dynamically?
(listProductx, listProductx2) => listProductx.ProductName == listProductx2.ProductName && listProductx.ProductCode == listProductx2.ProductCode && etc....
If you are going to use the comparison function (CompareValue<T1, T2> compareValue) a lot of times, then it would make sense to create an expression and compile it. Here is an example:
public static CompareValue<T1, T2> CreateComparer<T1, T2>(List<CompareColumns> columns)
{
var propertyNames = columns.Select(x => x.Columns).ToList();
var param1 = Expression.Parameter(typeof (T1), "val1");
var param2 = Expression.Parameter(typeof (T2), "val2");
var expressionBody =
propertyNames
.Select(propertyName =>
Expression.Equal(
Expression.Property(param1, propertyName),
Expression.Property(param2, propertyName)))
.Aggregate(Expression.AndAlso);
return
Expression
.Lambda<CompareValue<T1, T2>>(
expressionBody,
param1,
param2)
.Compile();
}
Here is how to use it:
List<CompareColumns> columns = ...
var func = CreateComparer<Class1,Class2>(columns);
var result = CompareTwoLists<Class1,Class2>(listOfClass1, listOfClass2 , func);
Assuming listCompareColumns can be defined in compareValue function you can do this using Reflection:
bool CmpVal<T1, T2>(T1 val1, T2 val2)
{
var listCompareColumns = new List<CompareColumns>();
//fill list values
return listCompareColumns
.All(q => typeof(T1).GetProperty(q.Columns, BindingFlags.Public |
BindingFlags.Instance)
.GetValue(val1) ==
typeof(T2).GetProperty(q.Columns, BindingFlags.Public |
BindingFlags.Instance)
.GetValue(val2));
}
Can I write this
return (a, b) => (b == 0) ? 0: a / b;
With an if-else to the right of (a, b) =>
If you are returning a Func<double, double, double> it could be re-written as
return (a, b) =>
{
if(b == 0)
return 0;
else
return a / b;
};
If you are returning a Expression<Func<double, double, double>> it is not very easy to do, you will need to create a custom Expression by hand to represent the statement as there is no way to represent it in C#.
Have not tested it, but I think the Expression version would be
public Expression<Func<double, double, double>> IThinkThisWorks()
{
var paramA = Expression.Parameter(typeof(double), "a");
var paramB = Expression.Parameter(typeof(double), "b");
var const0 = Expression.Constant(0.0);
var test = Expression.Equal(paramA, paramB);
var division = Expression.Divide(paramA, paramB);
var ifCheck = Expression.IfThenElse(test, const0, division);
return Expression.Lambda<Func<double, double, double>>(ifCheck, paramA, paramB);
}