I have a dictionary that uses strings as keys and Action functions as values.
Is there a way to define the dictionary without specifying the parameters of each key's function? For example, say I have a function foo(int a, string b). Is it possible to assign dict['test'] = foo?
I apologize if this question has been asked already -- I wasn't sure what to search for.
Yes, use Delegate instead of typed function. You'll call them with DynamicInvoke() and parameters can be passed with an array. In short:
Dictionary<string, Delegate>() _delegates;
void Test1(int a) { }
void Test2(int a, int b) { }
void SetUp() {
_delegates = new Dictionary<string, Delegate>();
_delegates.Add("test1", Test1);
_delegates.Add("test2", Test2);
}
void CallIt(string name, params object[] args) {
_delegates[name].DynamicInvoke(args);
}
Try it:
CallIt("test1", 1);
CallIt("test2", 1, 2);
Related
I have a dictionary that contains a string as a key, and a function to run when said string has been discovered. It then passes in the object used that was discovered. I merely want access to this object within the function body, but am unsure how to do it. I presume the lambda operator has to be used, but i don't really know how to properly use it.
public Dictionary<string, Func<object, bool>> stringReceivedRegister;
My setup
string received_name = StringFormater.GetName(receivedMessage);
object changed_string = openMethod.Invoke(instance, new object[] { receivedMessage });
StringTypes.Instance.stringReceivedRegister[received_name].Invoke(changed_string);
When adding a function to the stringReceivedRegister how would i access it within the function i pass in?
StringTypes.Instance.stringReceivedRegister.Add("Test", function where i can get access to 'changed string');
To add a function to stringReceivedRegister, your first need to declare a method:
private static bool MyFunction(object x) {
// ...
}
And then you can pass MyFunction to Add:
// Note the absence of () after "MyFunction". I am not actually calling it
stringReceivedRegister.Add("Test", MyFunction);
The x parameter will refer to changed_string when you do this:
StringTypes.Instance.stringReceivedRegister[received_name].Invoke(changed_string);
It's quite annoying to have to declare a method very time, so C# 3 provided lambda expressions, allowing you to do this:
stringReceivedRegister.Add("Test", x => {
// ...
});
Again, x will refer to changed_string when you invoke the delegate with changed_string.
Look at this code:
static bool FunctionTest(object o) {
return true;
}
static void Main(string[] args) {
Dictionary<string, Func<object, bool>> dict = new Dictonary<string, Func<object, bool>>();
dict.Add("A", ((obj) => { return false; }));
dict.Add("B", FunctionTest);
Console.WriteLine(dict["A"](1));
Console.WriteLine(dict["B"](1));
I am consuming some external library that have one method which except parameter as Func type.
class LibClass
{
public void libMethod(Func<int, int, int> add)
{
add(5, 5);
}
}
In my Console app i am consuming like
class Program
{
public static int MyMethod(int a, int b) // want to pass third parameter
{
return 0;
}
static void Main(string[] args)
{
LibClass obj = new LibClass();
obj.libMethod(Program.MyMethod);
Console.Read();
}
}
I want to pass some additional parameter to MyMethod(), but i am not able to pass it. so how can change library method signature?
or how i can pass additional parameter to MyMethod()?
You would have to recompile the library from source in order to change its methods, but I think this might be an XY Problem. You shouldn't need to change the signature to pass another parameter to your method. Example:
int DoSomeMath(int a, int b, int x)
{
return (a + b) * x;
}
If you wanted to have libMethod call DoSomeMath with more parameters, you can just wrap it in a lambda and add your own:
void Main()
{
LibClass obj = new LibClass();
obj.libMethod((a, b) => DoSomeMath(a, b, 42));
Console.Read();
}
The lambda will receive a and b from libMethod, pass those along with 42 to DoSomeMath, and return the return value of DoSomeMath back to libMethod.
All methods in the "ProbabilitiesTheory" class accept dynamic count of parameters - it means that there can be put as many parameters as one wants. But .NET still says "System.Reflection.TargetParameterCountException" when invoking a method, that has "params" keyword in its parameters.
Here's the code:
internal static class ProbabilitiesTheory
{
static public double GetMediumValue(params double[] integers)
{ }
}
class Program
{
static void Main(string[] args)
{
MethodInfo[] methods = Type.GetType("ConsoleApplication1.ProbabilitiesTheory").GetMethods();
while (true)
{
Console.WriteLine("Write the name of the method\n");
string NameOfMethod = Console.ReadLine();
Console.WriteLine("Write the parameters of the method using the following format:
parameter1;parameter2;parameter3;parameterN\n");
string ParametersOfMethod = Console.ReadLine();
foreach (var i in methods)
{
if (i.Name == NameOfMethod)
{
object[] #parameters = (from t in ParametersOfMethod.Split(';') where t != "" select (object)Convert.ToDouble(t)).ToArray();
i.Invoke(null, #parameters); // Exception HERE
}
}
Console.WriteLine("______");
}
}
}
It is absolutely ok with LINQ expression there, i get what i need to get: object[] containing dynamic amount of double values.
How do i solve this problem?
As far as reflection is concerned, a params array is just an array with a fancy syntactical sugar. You could solve the immediate problem for most of your methods by adjusting your code like so:
double[] #parameters = (from t in ParametersOfMethod.Split(';') where t != "" select Convert.ToDouble(t)).ToArray();
i.Invoke(null, new[] { #parameters});
The gist of this is that a params array is just a single parameter at run-time, and the ability to add a variable amount of values to it is just a nicety done by the compiler.
You can confirm this with a snippet like this:
void Main()
{
var parameterCount = typeof(Test).GetMethod("Foo").GetParameters().Count();
Console.WriteLine(parameterCount); // Output: 2
}
// Define other methods and classes here
public static class Test
{
public static void Foo(double x, params double[] y)
{}
}
If you need to invoke a function that uses a params array with user provided values when the params array is not the only parameter, you're going to need to get the method parameter count and work out where the array actually starts, then wrap things accordingly.
Ok, So I'm felling super lazy and I was wondering if I can call a function dynamically by a function pointer or something else somehow?
Instead of writing a bunch of if else I can put all possible functions in an array and pass which index I wan't to execute.
I was thinking of some sort of linkedlist.
eg.
//mainClass
private void initFunctionLL()
{
currNode.functionRef = this.funct1;
...
nextNode.functionRef = this.funct2;
}
private void callNext(){
currNode = currNode.Next();
currNode.execute();
}
//
//nodeClass
public void execute()
{
call myFunctionRef();
}
If your functions has the same return type and the same parameters list then you can use Func<T> or Action to make a set of delegates to this functions and call it. Example for functions without parameters which don't return a value:
private void ExecuteManyFunctions()
{
List<Action> actions = new List<Action>();
actions.Add(Foo);
actions.Add(Bar);
foreach(var func in actions)
func();
}
private void Foo() => { // some logic here }
private void Bar() => { // some logic here }
Another example for functions with integer parameter returns string:
private void ExecuteManyFunctions()
{
List<Func<string, int>> actions = new List<Func<string, int>>();
actions.Add(Foo);
actions.Add(Bar);
var results = new List<string>();
foreach(var func in actions)
results.Add(func(1));
}
private string Foo(int x) => { return x.ToString(); }
private string Bar(int y) => { return "staticResult"; }
You can add a bunch of Func or Action delegates to a list and then call each one. If your method takes no arguments and returns nothing, then use Action, if it takes one argument and returns nothing then use Action<T> wherein T specifies the type of argument. If it returns something then use Func<T>, wherein T specifies the return type. In Func<T> the last item specifies the return type and the ones before specify the argument types. Please see links at then end of my answer for more details. There are many Action and Func delegates with variable parameters. If none of them are satisfy your needs, then look into Delegate.
For example, in example below I am declaring a list which will hold a bunch of funcs which take one int and return one int. Then I am looping through and calling each one. First one multiplies the number passed to it and return the product, while the 2nd one adds the number to itself.
var funcs = new List<Func<int, int>>();
funcs.Add(x => x * x);
funcs.Add(x => x + x);
funcs.Add(x => Square(x)); // Or like this
foreach (var thisFunc in funcs)
{
thisFunc(5);
}
private static int Square(int number)
{
return number * number;
}
Please see Func and Action.
I want to create a generic to which I can pass a function as a parameter, however this function may include parameters itself so...
int foo = GetCachedValue("LastFoo", methodToGetFoo)
Such that:
protected int methodToGetFoo(DateTime today)
{ return 2; // example only }
Essentially I want to have a method that will check the cache for a value, otherwise will generate the value based on the passed in method.
Thoughts?
It sounds like you want a Func<T>:
T GetCachedValue<T>(string key, Func<T> method) {
T value;
if(!cache.TryGetValue(key, out value)) {
value = method();
cache[key] = value;
}
return value;
}
The caller can then wrap this in many ways; for simple functions:
int i = GetCachedValue("Foo", GetNextValue);
...
int GetNextValue() {...}
or where arguments are involved, a closure:
var bar = ...
int i = GetCachedValue("Foo", () => GetNextValue(bar));
Use System.Action and a lambda expression (anonymous method). For example:
public void myMethod(int integer) {
// Do something
}
public void passFunction(System.Action methodWithParameters) {
// Invoke
methodWithParameters();
}
// ...
// Pass anonymous method using lambda expression
passFunction(() => myMethod(1234));
You can create your own delegate, but in C# 3.0 you may find it more convenient to use the built-in Func<T> delegate family to solve this problem. Example:
public int GetCachedValue(string p1, int p2,
Func<DateTime, int> getCachedValue)
{
// do some stuff in here
// you can call getCachedValue like any normal function from within here
}
This method will take three arguments: a string, an int, and a function that takes a DateTime and returns an int. For example:
int foo = GetCachedValue("blah", 5, methodToGetFoo); // using your method
int bar = GetCachedValue("fuzz", 1, d => d.TotalDays); // using a lambda
Different Func<T, U, V...> etc. types exist in the framework to accommodate methods with different amounts of arguments.
Create a delegate for the method methodToGetFoo
public delegate object GenerateValue(params p);
public event GenerateValue OnGenerateValue;
Define GetCachedValue to use the delegate
int GetCachedValue(string key, GenerateValue functionToCall);
Then in the implementation of OnGenerateValue you can check the param's.
Here is something simple I started that can be taken a bit further (as I did for a commercial project).
In my case this was to cache web service calls, and was used something like:
WebService ws = new WebService();
var result = ws.Call( x => x.Foo("bar", 1)); // x is the ws instance