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.
Related
I am looking for a way to unfold a params object array casting to the correct argument type based on a given function signature as demonstrated in the following example:
public class Class {
public enum State { A, B, /* ...*/}
public void GenericFunction(State state, params object[] args) {
switch(state) {
case State.A: Apply(CaseA,args); break;
case State.B: Apply(CaseB,args); break;
/* ... */
}
}
public void CaseA(int i, string s) { /* ... */ }
public void CaseB(double[] ds) { /* ... */ }
public void ExampleInvocation() {
GenericFunction(State.A,10,"abc"); // supposed to call CaseA with arguments 10 and "abc"
GenericFunction(State.B,new double[] { 1.2, 3.5, 7.2}); // supposed to call CaseB
GenericFunction(State.A,6.66); // supposed to throw an exception
}
}
Is there a library or some feature in c# providing something like the method Apply?
You can do that using reflection. The price is performance and no compile time checks.
typeof(MyType).GetMethod("add").Invoke(null, new [] {arg1, arg2})
Example taken from: how to dynamically call a function in c#
To decide which function to use I'd inspect the available functions using reflection GetParameters() (see https://learn.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.getparameters) and cache the result to a Dictionary.
As others already mentioned: While this can be a valid way in special cases - in most cases it's not the way you should do it in C#.
So far I ended up doing something like
private void Apply(string functionName, object[] args) {
var methodInfo = typeof(Class).GetMethod(functionName, BindingFlags.Instance,
Type.DefaultBinder, args.Select(_ => _.GetType()).ToArray(), null);
if (methodInfo == null) {
// error handling - throw appropriate exception
} else {
methodInfo.Invoke(this, args);
}
}
This requires to change the original call of Apply(CaseA,args) to Apply(nameof(CaseA),args).
Any more elegant solution is still welcome.
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.
Regarding anonymous methods, and given a method "WriteConditional" that has the first parameter as a Func, is there a way to even eliminate the extra "() => " syntax?
It seems like you should be able to, since its unambiguous as long as there's no additional overload that would accept string, right?
void Program()
{
IDictionary<string,string> strings = new Dictionary<string,string>() { {"test","1"},{"test2","2"}};
//seems like this 'should' work, because WriteConditional has no other overload
//that could potentially make this ambiguous
WriteConditional(strings["test"],"<h3>{0}</h3>");
//since WriteConditional_2 has two overloads, one that has Func<string> and another with string,
//the call could be ambiguous, so IMO you'd definitely have to "declare anonymous" here:
WriteConditional_2(()=>strings["test"],"<h3>{0}</h3>");
}
void WriteConditional(Func<string> retriever, string format)
{
string value = retriever.Invoke();
if(string.IsNullOrEmpty(value)==false)
Console.WriteLine(string.Format(format,value));
}
void WriteConditional_2(Func<string> retriever, string format)
{
string value = retriever.Invoke();
if(string.IsNullOrEmpty(value)==false)
Console.WriteLine(string.Format(format,value));
}
void WriteConditional_2(string value, string format)
{
if(string.IsNullOrEmpty(value)==false)
Console.WriteLine(string.Format(format,value));
}
No, there is no such way. You could however, cheat and provide your own overload:
void WriteConditional(Func<string> retriever, string format)
{
var value = retriever();
if(string.IsNullOrEmpty(value)==false)
Console.WriteLine(string.Format(format,value));
}
void WriteConditional(string value, string format)
{
WriteConditional(() => value, format);
}
is there a way to even eliminate the extra "() => " syntax?
I also think the answer is no but you can do something if your func returns a custom class by using operator overloading.
This could be possible for other types if you could use operation overloading with extention methods
using System;
public class MyClass
{
public static implicit operator Func<MyClass>(MyClass obj)
{
return () => { Console.WriteLine("this is another cheat"); return new MyClass(); };
}
}
public class Program
{
static void Main(string[] args)
{
MyClass x = new MyClass();
WriteConditional(x);
Console.ReadLine();
}
static void WriteConditional(Func<MyClass> retriever) { }
}
Imagine in a class you got this Method:
float Do(int a_,string b_){}
I'm trying to do something like this:
float Do(int a_, string b_)
{
var params = GetParamsListOfCurrentMethod(); //params is an array that contains (a_ and b_)
}
Can someone help ?
Why should I want to do thet ?
Imagine you got an Interface:
public Interface ITrucMuch
{
float Do(int a_,string b_);
// And much more fct
}
And a lot of classes implementing that interface
And a special class that also implement interface:
public class MasterTrucMuch : ITrucMuch
{
public floatDo(int a_, string b_)
{
ITrucMuch tm = Factory.GetOptimizedTrucMuch(); // This'll return an optimized trucMuch based on some state
if(tm != null)
{
return tm.Do(a_,b_);
}
else
{
logSomeInfo(...);
}
//do the fallback method
}
As the interface constains a lot of method and as the first lien of all method are always the same (checking if there is a better interface that the current instance and if so call the same method on the instance) I try to make a method of it.
Thx
You could do something like this:
var parameters = MethodBase.GetCurrentMethod().GetParameters();
foreach (ParameterInfo parameter in parameters)
{
//..
}
Have a look at the ParameterInfo class.
var params = GetParamsListOfCurrentMethod();
params is a C# keyword so it can't be used as a variable name as above.
Here's a link on how to use the params keyword
http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
And some example code pulled form the article.
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}
Use Reflection .NET to get the parameter names for the method.
Using reflection to get method name and parameters
or
http://msdn.microsoft.com/en-us/library/system.reflection.parameterinfo.aspx
you can write your function with dynamic parameter like this:
protected void Do(params object[] list)
{
if (list.Length < 2)
return;
int a_=(int)list[0];
string b_=list[1].ToString();
}
I don't get it. If you want the param values, and this is the method you need to work with, what about simple doing
protected void Do(int a_, string b_)
{
var paramValues = new object[]{a_, b_};
}
Do you want a more generic answer? Then you are duplicating questions Can I get parameter names/values procedurally from the currently executing function? and How to get parameter value from StackTrace
And you can't, basically.
I've got a method that computes a list. At certain points in the algorithm a single element from the list needs to be chosen. It doesn't really matter which element is chosen, but I'd like to leave it up to the user to decide.
Right now, I've added an extension method IList<T>.Random() which simply takes a random element. .First() would have worked equally as well. Supposing I want to let the user pick which method is used, or perhaps an entirely different method, how would that look?
I was thinking about using an enum with limited options, and then I could wrap each of these calls in a switch and call the appropriate function. But maybe some sort of lambda function would be more appropriate?
This method needs to be used in two different places, once on a List<char> and once on a List<string>. I want to use the same method for both.
This isn't a GUI app. I'm trying to decide how to design the API.
Specifically, I want to have a field like
public Func<IList<T>, T> SelectElement = list => list.First();
Which would then be used in the method,
public string Reverse(string pattern, IList<object> args = null, IDictionary<string, object> kwargs = null)
But generic fields aren't possible. So I'm looking for an alternative solution. One would be to make the SelectElement method an argument to Reverse(), then I could make it generic... but I was hoping to keep it at a class-level for re-usability. Don't want to pass any more args to the function if I can help it.
Edit: full source code
how about this:
public class MyClass
{
public static class C<T>
{
public static Func<IList<T>, T> SelectElement;
}
public int Test(IList<int> list)
{
return C<int>.SelectElement(list);
}
}
static class Program
{
static void Main(string[] args)
{
MyClass.C<char>.SelectElement = xs => xs.First();
MyClass.C<int>.SelectElement = xs => xs.First();
var list = new List<int>(new int[] { 1, 2, 3 });
var c = new MyClass();
var v = c.Test(list);
Console.WriteLine(v);
}
}
Here's an extremely basic example I put together using a generic method that takes in a Func<IEnumerable<T>, T> for selecting an item from the list and then returns the result. I've done a few examples of how to call it:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
//Simple list.
var list = new List<int> { 1, 2, 3, 4 };
// Try it with first
var result = DoItemSelect(list, Enumerable.First);
Console.WriteLine(result);
// Try it with last
result = DoItemSelect(list, Enumerable.Last);
Console.WriteLine(result);
// Try it with ElementAt for the second item (index 1) in the list.
result = DoItemSelect(list, enumerable => enumerable.ElementAt(1));
Console.WriteLine(result);
}
public static T DoItemSelect<T>(IEnumerable<T> enumerable, Func<IEnumerable<T>, T> selector)
{
// You can do whatever you method does here, selector is the user specified func for
// how to select from the enumerable. Here I just return the result of selector directly.
return selector(enumerable);
}
}
}
If you want to limit the choices a user has you could follow the route of an enum and make this method a private method and then have a way to convert the enum to the appropriate selector delegate to pass to the underlying private method.
public Func<IList<object>, object> SelectElement = list => list.First();
private T _S<T>(IEnumerable<T> list)
{
return (T)SelectElement(list.Cast<object>().ToList());
}
I can make the anonymous method work on objects, thereby avoiding generics, and then add a helper method which is what I'll actually use to call it. A little ugly, but seems to work.
This works for chars and strings. Haven't tested with other types. Built this before I saw Ralph's code, which is practically the same.
LINQPad code:
void Main()
{
var chars = new List<char>();
var strings = new List<string>();
chars.AddRange(new char[] {'1','2','4','7','8','3'});
strings.AddRange(new string[] {"01","02","09","12","28","52"});
chars.Dump();
strings.Dump();
Func<IList<object>, string> SelectFirst = ( list )
=> list.First().ToString();
Func<IList<object>, string> SelectLast = ( list )
=> list.Last().ToString();
Func<IList<object>, string> SelectRandom = ( list )
=> list.ElementAt( new Random().Next(0, list.Count())).ToString();
SelectBy(SelectFirst, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectFirst, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, chars.Cast<object>().ToList()).Dump();
}
private string SelectBy(Func<IList<object>, string> func, IList<object> list)
{
return func(list);
}