Can not use Func with parameters - c#

I have an example for my problem.
Basically i need to pass a method to another method with parameters included.
public void test() {
var test = Add(Domath(5, 5)); // should be 10
}
public int Domath (int a, int b) {
return a + b;
}
public int Add (Func<int, int, int> math){
return math();
}
It does not work this way and i don‘t know why. This is just a minimalistic example. Is there a way to get this working?

Let's have a look at
public int Add (Func<int, int, int> math){
return math();
}
You can't return return math();: note, that math requires two arguments which are not passed to math(). You can modify Add as
public int Domath (int a, int b){
return a + b;
}
// We are going to add first and second
// with a help of math function
public int Add (int first, int second, Func<int, int, int> math = null) {
// If math is not provided, we use Domath functon
if (math == null)
math = Domath;
// Finally, we call math with required two arguments
return math(first, second);
}
Now you can put
public void test(){
var test = Add(5, 5);
}
Or
public void test(){
var test = Add(5, 5, Domath);
}

Related

Create list of Methods to run on Dynamic Objects

So let's say I have some number methods that are already defined for a class.
For Example:
private int X(int a, int b)
{
return a + b;
}
private int Y(int a, int b)
{
return a - b;
}
private int Z(int a, int b)
{
return a * b;
}
Now the standard way to take an input in the main body of the class and run it through all the functions would obviously be to just call every function like this:
public void processNormal(int a, int b)
{
//accumulate results
int acc = 0;
if (true)
{
//if want to add to current
acc += X(a, b);
acc += Y(a, b);
acc += Z(a, b);
}
else
{
//if want to replace current if larger
int k = X(a, b);
if (k > acc)
acc = k;
k = Y(a, b);
if (k > acc)
acc = k;
k = Z(a, b);
if (k > acc)
acc = k;
}
}
Now I was curious, since as the number of functions grows, depending on how many things you may want to do with the function results grows, if that doesn't become a bit cumbersome. And you could instead create a static list of the functions you'll want to run, and then use that in a for loop to shorten things down, which I would imagine would look something like this:
//List with all methods
List<Object> methods = new List<Object>();
//add all methods to list
public void processWithList(int a, int b)
{
//accumulate results
int acc = 0;
foreach (Object j in methods)
{
if (true)
{
//if want to add to current
acc += j(a, b);
}
else
{
//if want to replace current if larger
int k = j(a, b);
if (k > acc)
acc = k;
}
}
}
Now with this second process, you still have to define the list somewhere, but I imagine it is easier to keep track of as things grow. All the functions would take the same inputs, and return the same objects so in that regard it's not an issue.
I'm basically wondering if
A) I'm stupidly over complicating things and if this would ever be a useful thing to do.
B) What would such a thing look like in C#? Could I use the predefined class methods in a list or would I have to generate the list in the class' initialization with a bunch of delegate functions?
Thank you for your time.
Am I stupidly over complicating things and if this would ever be a useful thing to do?
No, You're doing just fine. This is a common approach.
What would such a thing look like in C#?
I think the simplest option that matches your sample code is using a List<Func<int, int, int>>.
Here is a sample implementation:
public class YourClass
{
private List<Func<int, int, int>> methods;
public yourClass()
{
methods = new List<Func<int, int, int>>()
{
(a,b) => X(a,b),
(a,b) => Y(a,b),
(a,b) => Z(a,b)
};
}
public int SumMethods(int a, int b)
{
var result = 0;
foreach(var m in methods)
{
result += m(a, b);
}
return result;
}
private int X(int a, int b) { throw new NotImplementedException(); }
private int Y(int a, int b) { throw new NotImplementedException(); }
private int Z(int a, int b) { throw new NotImplementedException(); }
}

C# extension using function Func as parameter

Please don't be confuse with the code, the code is wrong. Focused on the bold question below.
I've been preparing to study functional programming and just so at least be ready for its prerequisites, I've been studying extensions, functions and lambda expressions.
This code below is NOT working I just thought this is how it should be coded:
Program:
class Program
{
static void Main(string[] args)
{
int s = 10;
int t = s.CreatedMethod(2, 3); // <-- the one that calls the extension
Console.WriteLine(t.ToString());
Console.ReadLine();
}
static int RegularMethod(int v1, int v2)
{
return v1 * v2; // <-- I also wanted to multiply int 's' like this s*v1*v2
}
}
Extension:
public static class Extension
{
public static int CreatedMethod(this int number, Func<int, int, int> fn)
{
// I'm expecting that the code here will read the
// RegularMethod() above
// But I don't know how to pass the parameter of the function being passed
return #fn(param1, param2)// <-- don't know how to code here ??
}
}
As you can see, the CreateMethod extended my integer 's'. My plan is to pass the two parameters in CreateMethod() above and multiply those two parameters into 's'
In the example above, the answer should be 60.
Can you help me do it using extension?
This might be what you're looking for but it doesn't make sense to pass a function as a parameter or maybe I'm just missing something. Anyway, it works:
class Program
{
static void Main(string[] args)
{
int s = 10;
// the function we're passing as a parameter will multiply them
// then return the result
int t = s.CreatedMethod((param1, param2) => param1 * param2);
// or you can use this since the method signature matches:
// int t = s.CreatedMethod(RegularMethod);
Console.WriteLine(t.ToString()); // outputs "60"
Console.ReadLine();
}
static int RegularMethod(int v1, int v2)
{
return v1 * v2; // <-- I also wanted to multiply int 's' like this s*v1*v2
}
}
public static class Extension
{
public static int CreatedMethod(this int number, Func<int, int, int> fn)
{
return number * fn.Invoke(2, 3);
}
}
Following up on OP's comment: If you don't want to hardcode the values then you'll need to change the CreateMethod's signature to this:
public static int CreatedMethod(this int number, int val1, int val2, Func<int, int, int> fn)
then call Invoke like this:
fn.invoke(val1, val2)
Extension could look like this:
public static int CreatedMethod(this int number1, int number2, Func<int, int, int> fn) {
fn(number1, number2);
}
And then call would be:
var s = 10;
var t = s.CreatedMethod(2, RegularMethod).
CreatedMethod(3, RegularMethod);
This will first call RegularMethod with 10 and 2 and second time with 20 and 3.
Additional way would be to use extension like
public static int CreatedMethod(this int number1, int number2, int number3, Func<int, int, int> fn) {
fn(fn(number1, number2), number3);
}
And call like
var s = 10;
var t = s.CreatedMethod(2, 3, RegularMethod);

How to declare a delegate that can take an enum which is not known until runtime?

I have a client application that uses classes (and enums) from an external dll which is loaded at runtime and reflected. I know what methods I am expecting to find in the dll and what I am expecting its enums to be called.
I would like to create a delegate that I can use in the client application and which is created from the reflected method at runtime. This approach works when the delegate just has "standard" types, but how can I get this to work if the dll method takes an enum? I can't declare the enum in the delegate as an object since it's a value type, trying the Enum or int does not seem to work either. Is there a way around this? Any help gratefully received!
// e.g. external code
namespace test2
{
public static class test2
{
public static int calc(int a, int b, testEnum c)
{
if (c == testEnum.add) return a + b;
else return a - b;
}
public static int add(int a, int b)
{
return a + b;
}
}
public enum testEnum
{
add, subtract
}
}
// my client code
namespace test1
{
public class TestClient
{
private static Assembly _assembly;
public static void SetUp()
{
const string externalDll = ".../test2.dll";
Assembly assembly = Assembly.LoadFrom(externalDll);
AppDomain.CurrentDomain.Load(assembly.GetName());
_assembly = assembly;
}
private delegate int _add(int a, int b);
private _add add;
private delegate int _calc(int a, int b, ??? c); // nothing works here
private _calc calc;
public void Run()
{
SetUp();
add = GetExpectedFunction<_add>("add");
int three = add(1, 2); // OK
calc = GetExpectedFunction<_calc>("calc"); // not OK
// intended usage
var reflectedEnum = ReflectMe("testEnum", "add");
int threeAgain = calc(1, 2, reflectedEnum);
}
public static T GetExpectedFunction<T>(string functionName) where T : class
{
try
{
if (!typeof(T).IsSubclassOf(typeof(Delegate))) throw new ApplicationException("GetExpectedFunction must return a delegate!");
var foundMethod = _assembly.GetType("test2.test2").GetMethod(functionName, BindingFlags.Public | BindingFlags.Static);
return (T)(object)Delegate.CreateDelegate(typeof(T), foundMethod);
}
catch (Exception e)
{
// "Error binding to target method!"
}
}
}
}
You can bind a delegate with object type to a method taking an enum by creating, at runtime, a dynamic method call with LINQ Expression, and adding data conversions for parameters whose types don't match:
public static T GetExpectedFunction<T>(string functionName) where T : class {
try {
if (!typeof(T).IsSubclassOf(typeof(Delegate))) throw new ApplicationException("GetExpectedFunction must return a delegate!");
var foundMethod = Type.GetType("test2.test2").GetMethod(functionName, BindingFlags.Public | BindingFlags.Static);
var inv = typeof(T).GetMethod("Invoke");
var parameters = inv.GetParameters().Zip(foundMethod.GetParameters(), (a, b) => new {
PassedIn = a.ParameterType
, Reflected = b.ParameterType
, Parameter = Expression.Parameter(a.ParameterType)
}).ToList();
if (parameters.All(p => p.PassedIn == p.Reflected)) {
// Bind directly
return (T)(object)Delegate.CreateDelegate(typeof(T), foundMethod);
}
var call = Expression.Call(foundMethod, parameters.Select(
p => p.PassedIn==p.Reflected
? (Expression)p.Parameter
: Expression.Convert(p.Parameter, p.Reflected)
));
return (T) (object) Expression.Lambda(typeof(T), call, parameters.Select(p => p.Parameter)).Compile();
} catch (Exception e) {
// "Error binding to target method!"
return null;
}
}
This implementation pairs up types from the reflected and the delegate methods (see parameters variable), and creates ParameterExpression objects for types that come from the delegate. Then it checks if all parameter types match up (the parameters.All(...) part). This is an optimization for situations when conversions are unnecessary.
If at least one conversion is necessary, the code creates a method call that substitutes the original parameter expressions with conversion expressions where types do not match up, creates a lambda of the requested delegate type, compiles it, and returns it to the caller.
For your code this dynamic method would look like this:
int dynamic_method(int a, int b, object c) {
return test2.test2(a, b, (testEnum)c);
}
There is one solution, you have to create faked Enum (it will be better if you create the exact enum), then you will pass as integer like this:
private delegate int _add(int a, int b);
private _add add;
private delegate int _calc(int a, int b, FakedEnum c); // faked enum here
private _calc calc;
public enum FakedEnum
{
}
public void Run()
{
SetUp();
add = GetExpectedFunction<_add>("add");
int three = add(1, 2); // OK
calc = GetExpectedFunction<_calc>("calc"); // it will be ok
var result= calc(4, 6, (FakedEnum)0);
// intended usage
// var reflectedEnum = ReflectMe("testEnum", "add");
//int threeAgain = calc(1, 2, reflectedEnum);
}
Use dynamic keyword to declare your delegate parameter:
private delegate int _calc(int a, int b, dynamic c);

How, if possible, can you pass in a C# Property to be used like a method?

I know Func<> is used to pass a method that has a return value to be used inside another method. I know Action<> is used to pass a method that does not have a return value to be used inside another method. Is there a way to pass in a property so it's get/set can be used inside another method?
For example, here is a method that uses Func<>:
public bool RangeCheck (int minVal, int maxVal, Func<< int, int >> someMethod)
{
bool retval = true;
try
{
for (int count = min; count <= max; count++)
{
int hello = someMethod(count);
}
}
catch
{
retval = false;
}
return retval;
}
What I am looking for is something like this:
public bool RangeCheck(int min, int max, Prop<< int >> someProperty)
{
bool retval = true;
try
{
for (int count = min; count <= max; count++)
{
someProperty = count;
}
}
catch
{
retval = false;
}
return retval;
}
Is there anything out there like this? I can't find anything. This would be very useful. Thanks.
Could you use a lambda as a wrapper?
MyClass myClass = new MyClass();
bool val = RangeCheck(0, 10, () => myClass.MyProperty);
If you're looking to do both, you would make two lambdas, one for set, and one for get.
bool val = RangeCheck(0, 10, () => myClass.MyProperty, (y) => myClass.MyProperty = y);
My syntax is probably off, but I think this gives the idea.
Not that I know of. You could try using reflection and pass the object along with the corresponding PropertyInfo object of the property you want to get the value of. You then call PropertyInfo's SetValue function to assign a value to it (assuming it's read/write, of course).
public void SetMyIntValue()
{
SetPropertyValue(this, this.GetType().GetProperty("MyInt"));
}
public int MyInt { get; set; }
public void SetPropertyValue(object obj, PropertyInfo pInfo)
{
pInfo.SetValue(obj, 5);
}
Why not simply make it a ref argument?
public bool RangeCheck(int min, int max, ref int someProperty)
You can now set the value of someProperty inside the method.
And call it like so:
RangeCheck(min, max, ref myProperty);
You could use a Func like this Func<int, T>
void Main()
{
var sc = new SimpleClass();
var result = RangeCheck(0, 10, x => sc.Value = x );
System.Console.WriteLine(result);
System.Console.WriteLine(sc.Value);
}
public class SimpleClass
{
public int Value { get; set; }
}
public bool RangeCheck<T>(int minVal, int maxVal, Func<int, T> someMethod)
{
bool retval = true;
try
{
for (int count = minVal; count <= maxVal; count++)
{
//someMethod(count); //is not a range check,
//Did you mean
someMethod(count - minValue);
}
}
catch
{
retval = false;
}
return retval;
}

add(a,b) and a.add(b)

how can i transform a method (that performs a+b and returns the result) from add(a,b) to a.add(b)?
i read this somewhere and i can't remember what is the technique called...
does it depends on the language?
is this possible in javascript?
In .NET it is called extension methods.
public static NumberExtensions
{
public static int Add(this int a, int b)
{
return a + b;
}
}
UPDATE:
In javascript you could do this:
Number.prototype.add = function(b) {
return this + b;
};
var a = 1;
var b = 2;
var c = a.add(b);
On c# it is named extensions methods:
public static class IntExt
{
public static int Add(this int a, int b)
{
return a + b;
}
}
...
int c = a.Add(b);
say for example you want to do this on integers in C#. You need to define extension methods like this:
public static class IntExtMethods
{
public static int add(this int a, int b)
{
return a+b;
}
}
In C# you can use an Extension Method. In C++, you need to create a member which belongs to the A class which performs the add for you. C does not have objects, so what you're looking for is not possible in C.
If you want to create your own JavaScript class:
function Num(v) {
this.val = v;
}
Num.prototype = {
add: function (n) {
return new Num(this.val + n.val);
}
};
var a = new Num(1);
var b = new Num(2);
var c = a.add(b); // returns new Num(3);
Taking your question literally, I assume you mean transforming this
var add = function(a, b) {
return a + b;
}
to this:
a.add = function(b) {
return this + b;
}
This however only adds that method to a, not to any other object with the same constructor. See Darin Dimitrov's answer for an example of that. Extending the native Number constructor's prototype is not something many would recommend though...

Categories