C# - pass on expanded params array to another function - c#

How can I expand a params array when passing it on to another function.
Consider the following example:
public class TestClass
{
public static void Main()
{
TestParamFunc(1, "1", 1.0f, 1.0);
Console.ReadKey();
}
private static void TestParamFunc(params object[] parameters)
{
//At the moment the DeeperTestParamFunc receives the following parameters: { int, object[] }
//How to expand this to { int, int, string, float, double } ?
//So that { 1, 1, "1", 1.0f, 1.0 } is received.
DeeperTestParamFunc(1, parameters);
}
public static void DeeperTestParamFunc(params object[] parameters)
{
foreach(object obj in parameters)
{
Console.WriteLine(obj.GetType().ToString());
}
}
}
Output:
System.Int32
System.Object[]
The output that I would like to have:
System.Int32
System.Int32
System.String
System.Single
System.Double

You make a new array, copy the existing parameters into it, add more things and call the other method with the larger array
These are, when all is said and done, just arrays. params just means the compiler lets you specify arguments individually and it will turn it into an array for you
You write this:
MyFuncWithParamsObjectArg(1,2,3,4,5);
The compiler conceptually changes it to:
MyFuncWithParamsObjectArg(new object [] {1,2,3,4,5} );
Here's a demo program:
public static void Main()
{
A("z", "y");
}
static void A(params object[] a){
Console.WriteLine("In A()");
foreach(object o in a)
Console.WriteLine(o);
object[] oo = new object[a.Length + 2];
for(int i = 0; i < a.Length; i++)
oo[i] = a[i];
oo[a.Length] = "new";
oo[a.Length + 1] = "new2";
B(oo);
}
static void B(params object[] b){
Console.WriteLine("In B()");
foreach(object o in b)
Console.WriteLine(o);
}
Prints out this:
In A()
z
y
In B()
z
y
new
new2
You can see that B was called with an array 2 longer than a, and added two more elements
Note, you can't "expand" an array, regardless of whether it's params or not. You have to make a new array, copy the stuff over, and go from there
If you're looking to wrap it up so that you're not flattening the first array, but instead making another params array that has the first array as one of its elements:
static void A(params object[] a){
Console.WriteLine("In A()");
foreach(object o in a)
Console.WriteLine(o);
B(a, "new1", "new2");
}
B will now get an array that looks like:
object[] {
object[] { "z", "y" },
"new1",
"new2"
}
As noted; there is no magic - the compiler looks at what you provided and if the arguments match "called with a single dimension array" then it calls the function with the array, otherwise it scoops up the various arguments, turns them into an array, and calls it with that array
B(a); //a is already an object array, it is passed in verbatim
B(a, "new1", "new2"); //a new object array is created from these 3 objects
B(new object[] {a, "new1", "new2"} ); //manually doing what the compiler does for you above

this is what you want:
private static void TestParamFunc(params object[] parameters)
{
// manually create the array in the form you need
var deeperParameters = new object[parameters.Length + 1];
deeperParameters[0] = 1;
parameters.CopyTo(deeperParameters, 1);
DeeperTestParamFunc(deeperParameters);
}

try :
public static void DeeperTestParamFunc(params object[] parameters)
{
foreach (object obj in (IEnumerable) parameters[1])
{
Console.WriteLine(obj.GetType().ToString());
}
}
instance :
public static void DeeperTestParamFunc(params object[] parameters)
{
foreach(object obj in parameters)
{
Console.WriteLine(obj.GetType().ToString());
}
}

Related

C# expand array to be arguments

void foo(int one, int two) {
}
public static void Main(string[] args) {
var bar = new int[] { 1, 2 };
foo(params bar);
}
What's the correct syntax to deconstruct the bar array and pass it as the arguments to the foo method?
In some other languages you can use a splat operator foo(...bar) or an unpack operator foo(*bar).
How can I do it in C#?
There isn't an equivalent function in C#. Each argument has to be passed individually.
There are, of course, work arounds that you likely already know. You could declare an overload for your function that would accept an array and call the original function using the first two inputs. The other alternative that I can think of is to declare the function parameter with the params keyword so that it could receive an array or multiple conma-separated elements when called.
void foo(params int[] numbers)
{ // TODO: Validate numbers length
int one = numbers[0];
int two = numbers[1];
}
public static void Main(string[] args) {
var bar = new int[] { 1, 2 };
// both valid function calls below
foo(bar);
foo(bar[0], bar[1]);
}
You can always use Reflection for such purpose.
Here is example snippet on your example method:
class MainClass
{
void foo(int one, int two)
{
Console.WriteLine(one + two);
}
static void Main()
{
var myInstance = new MainClass();
var bar = new object[] { 1, 2 };
var method = myInstance.GetType().GetMethod(nameof(MainClass.foo), BindingFlags.NonPublic | BindingFlags.Instance)
?? throw new InvalidOperationException($"Method '{nameof(MainClass.foo)}' not found");
method.Invoke(myInstance, bar) ;
}
}

Pass any method of an object as a paramter in a function

The title is may be not clear enough, but I'll show you a short program in order to make you understand what I want to do:
Class Program
{
private static Obj A = new Obj(...);
private static void Function(AnyMethodOfMyObject() m)
{
object[] result = A.m();
...
}
static void main()
{
double a,b,c = 0;
string d = " ";
Function(MethodX(a,b,c));
Function(MethodY(d,a,b));
...
}
}
The methods will always return the same type which is an object[], but I don't have the same number/type of argument.
Thanks !
You can do this simply with a Func<object[]>:
class Program
{
private static Obj A = new Obj(...);
private static void Function(Func<object[]> m)
{
object[] result = m();
...
}
static void main()
{
double a,b,c = 0;
string d = " ";
Function(() => A.MethodX(a,b,c));
Function(() => A.MethodY(d,a,b));
...
}
}
Func<object[]> is a delegate (broadly, a reference to a method) which does not take any parameters, and which returns an array of objects. While MethodX takes 3 parameters (a,b,c), we can create a new anonymous method without doesn't take any parameters itself, and which just calls MethodX and passes in the values of a, b and c (they're captured at the point that we create this new anonymous method). This is what () => MethodX(a, b, c) does.
If you have different Obj instances and you want to control which one the method is called on, then use a Func<Obj, object[]>. This takes an Obj as a parameter, and returns an object[] as before.
class Program
{
private static Obj A = new Obj(...);
private static void Function(Func<Obj, object[]> m)
{
object[] result = m(A);
...
}
static void main()
{
double a,b,c = 0;
string d = " ";
Function(x => x.MethodX(a,b,c));
Function(x => x.MethodY(d,a,b));
...
}
}

Calling a function using reflection that has a "params" parameter (MethodBase)

I have MethodBases for two functions:
public static int Add(params int[] parameters) { /* ... */ }
public static int Add(int a, int b) { /* ... */ }
I have a function that calls the MethodBases via a class I made:
MethodBase Method;
object Target;
public object call(params object[] input)
{
return Method.Invoke(Target, input);
}
Now if I AddTwoMethod.call(5, 4); it works fine.
If I however use AddMethod.call(5, 4); it returns:
Unhandled Exception: System.Reflection.TargetParameterCountException: parameters do not match signature
Is there any way to make it so that both calls work fine without need for manually putting the arguments in an array for the params int[]?
You could modify your call method to detect the params parameter and convert the rest of the input to a new array. That way your method could act pretty much the same as the logic C# applies to the method calling.
Something i quicly constructed for you (be aware that i tested this method in a pretty limited way, so there might be errors still):
public object call(params object[] input)
{
ParameterInfo[] parameters = Method.GetParameters();
bool hasParams = false;
if (parameters.Length > 0)
hasParams = parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0;
if (hasParams)
{
int lastParamPosition = parameters.Length - 1;
object[] realParams = new object[parameters.Length];
for (int i = 0; i < lastParamPosition; i++)
realParams[i] = input[i];
Type paramsType = parameters[lastParamPosition].ParameterType.GetElementType();
Array extra = Array.CreateInstance(paramsType, input.Length - lastParamPosition);
for (int i = 0; i < extra.Length; i++)
extra.SetValue(input[i + lastParamPosition], i);
realParams[lastParamPosition] = extra;
input = realParams;
}
return Method.Invoke(Target, input);
}
Be aware that i tested this method in a pretty limited way, so there might be errors still.
Supposing we have the following example class:
public class Test
{
public static int Add(int i1, int i2)
{
return i1 + i2;
}
public static int Add(params int[] ints)
{
int sum = 0;
foreach (int i in ints)
sum += i;
return sum;
}
}
To get the MethodInfo objects for each overload of the static Add method you should do the following:
MethodInfo Add2Ints = typeof(Test).GetMethod("Add", new Type[] { typeof(int), typeof(int) });
MethodInfo AddParamsInts = typeof(Test).GetMethod("Add", new Type[] { typeof(int[]) });
In order to invoke any of the two methods, symply pass the arguments with the exact type expected by the specific overload you are invoking:
Add2Ints.Invoke(null, new object[] { 1, 2 });
AddParamsInts.Invoke(null, new object[] { new int[] { 1, 2 } });
Note that the following will not work:
AddParamsInts.Invoke(null, new object[] { 1, 2 });
because the signature of AddParmsInt is really (int[]) and although the compiler, as a courtesy, allows you to call such method as (int, int) under the hood what is really happening is that the call is converted for you at the call site to the equivalent (int[]) call. Via reflection you don't have the compiler's "help" so you need to pass the exact argument type defined by the method's signature.
With all that said, your call method should be as follows:
public object call(params object[] input)
{
return AddParamsInts.Invoke(null /*static*/, new object[] { input.Cast<int>().ToArray() });
}
Note that you can not directly cast a object[] array to a int[] array: int[] ints = (int[])input. Casting reference typed arrays to value-type arrays is not allowed.
Also important to note is that the defined overloads of the Add method are useless, as they overlap. Consider only using the params overload or, in case you want to guarantee that at least two arguments are needed in order to evaluate an addition, overload them the following way:
public int Add(int i1, int i2) { }
public int Add(int i1, int i2, params int[] args) { }
You should wrap the arguments in an array, but the compiler will be confused, so you need to help it a bit:
Eg:
AddMethod.call((object) new int[] {5, 4 });

Function pointers in C#

I suppose in some ways either (or both) Delegate or MethodInfo qualify for this title. However, neither provide the syntactic niceness that I'm looking for. So, in short, Is there some way that I can write the following:
FunctionPointer foo = // whatever, create the function pointer using mechanisms
foo();
I can't use a solid delegate (ie, using the delegate keyword to declare a delegate type) because there is no way of knowing till runtime the exact parameter list. For reference, here's what I've been toying with in LINQPad currently, where B will be (mostly) user generated code, and so will Main, and hence for nicety to my users, I'm trying to remove the .Call:
void Main()
{
A foo = new B();
foo["SomeFuntion"].Call();
}
// Define other methods and classes here
interface IFunction {
void Call();
void Call(params object[] parameters);
}
class A {
private class Function : IFunction {
private MethodInfo _mi;
private A _this;
public Function(A #this, MethodInfo mi) {
_mi = mi;
_this = #this;
}
public void Call() { Call(null); }
public void Call(params object[] parameters) {
_mi.Invoke(_this, parameters);
}
}
Dictionary<string, MethodInfo> functions = new Dictionary<string, MethodInfo>();
public A() {
List<MethodInfo> ml = new List<MethodInfo>(this.GetType().GetMethods());
foreach (MethodInfo mi in typeof(Object).GetMethods())
{
for (int i = 0; i < ml.Count; i++)
{
if (ml[i].Name == mi.Name)
ml.RemoveAt(i);
}
}
foreach (MethodInfo mi in ml)
{
functions[mi.Name] = mi;
}
}
public IFunction this[string function] {
get {
if (!functions.ContainsKey(function))
throw new ArgumentException();
return new Function(this, functions[function]);
}
}
}
sealed class B : A {
public void SomeFuntion() {
Console.WriteLine("SomeFunction called.");
}
}
You say you want to keep the number and type of parameters open, but you can do that with a delgate:
public delegate object DynamicFunc(params object[] parameters);
This is exactly the same thing you currently have. Try this:
class Program
{
static void Main(string[] args)
{
DynamicFunc f = par =>
{
foreach (var p in par)
Console.WriteLine(p);
return null;
};
f(1, 4, "Hi");
}
}
You can think of an instance-method delegate as very similar to your Function class: an object an a MethodInfo. So there's no need to rewrite it.
Also function pointers in C and C++ are not any closer to what you need: they cannot be bound to an object instance and function, and also they are statically typed, not dynamically typed.
If you want to "wrap" any other method in a DynamicFunc delegate, try this:
public static DynamicFunc MakeDynamicFunc(object target, MethodInfo method)
{
return par => method.Invoke(target, par);
}
public static void Foo(string s, int n)
{
Console.WriteLine(s);
Console.WriteLine(n);
}
and then:
DynamicFunc f2 = MakeDynamicFunc(null, typeof(Program).GetMethod("Foo"));
f2("test", 100);
Note that I'm using a static method Foo so I pass null for the instance, but if it was an instance method, I'd be passing the object to bind to. Program happens to be the class my static methods are defined in.
Of course, if you pass the wrong argument types then you get errors at runtime. I'd probably look for a way to design your program so that as much type information is captured at compile time as possible.
Here's another bit of code you could use; Reflection is rather slow, so if you expect your Dynamic function calls to be called frequently, you don't want method.Invoke inside the delegate:
public delegate void DynamicAction(params object[] parameters);
static class DynamicActionBuilder
{
public static void PerformAction0(Action a, object[] pars) { a(); }
public static void PerformAction1<T1>(Action<T1> a, object[] p) {
a((T1)p[0]);
}
public static void PerformAction2<T1, T2>(Action<T1, T2> a, object[] p) {
a((T1)p[0], (T2)p[1]);
}
//etc...
public static DynamicAction MakeAction(object target, MethodInfo mi) {
Type[] typeArgs =
mi.GetParameters().Select(pi => pi.ParameterType).ToArray();
string perfActName = "PerformAction" + typeArgs.Length;
MethodInfo performAction =
typeof(DynamicActionBuilder).GetMethod(perfActName);
if (typeArgs.Length != 0)
performAction = performAction.MakeGenericMethod(typeArgs);
Type actionType = performAction.GetParameters()[0].ParameterType;
Delegate action = Delegate.CreateDelegate(actionType, target, mi);
return (DynamicAction)Delegate.CreateDelegate(
typeof(DynamicAction), action, performAction);
}
}
And you could use it like this:
static class TestDab
{
public static void PrintTwo(int a, int b) {
Console.WriteLine("{0} {1}", a, b);
Trace.WriteLine(string.Format("{0} {1}", a, b));//for immediate window.
}
public static void PrintHelloWorld() {
Console.WriteLine("Hello World!");
Trace.WriteLine("Hello World!");//for immediate window.
}
public static void TestIt() {
var dynFunc = DynamicActionBuilder.MakeAction(null,
typeof(TestDab).GetMethod("PrintTwo"));
dynFunc(3, 4);
var dynFunc2 = DynamicActionBuilder.MakeAction(null,
typeof(TestDab).GetMethod("PrintHelloWorld"));
dynFunc2("extraneous","params","allowed"); //you may want to check this.
}
}
This will be quite a bit faster; each dynamic call will involve 1 typecheck per param, 2 delegate calls, and one array construction due to the params-style passing.

How to convert delegate to object in C#?

I am using reflection class to invoke some methods which are on the some other dll.
And one of the methods' parameters are type of delegate.
And I want to invoke this methods by using reflection.
So I need to pass function parameters as object array, but I could not find anything about
how to convert delegate to object.
Thanks in advance
A delegate is an object. Just create the expected delegate as you would normally, and pass it in the parameters array. Here is a rather contrived example:
class Mathematician {
public delegate int MathMethod(int a, int b);
public int DoMaths(int a, int b, MathMethod mathMethod) {
return mathMethod(a, b);
}
}
[Test]
public void Test() {
var math = new Mathematician();
Mathematician.MathMethod addition = (a, b) => a + b;
var method = typeof(Mathematician).GetMethod("DoMaths");
var result = method.Invoke(math, new object[] { 1, 2, addition });
Assert.AreEqual(3, result);
}
Instances of delegates are objects, so this code works (C#3 style) :
Predicate<int> p = (i)=> i >= 42;
Object[] arrayOfObject = new object[] { p };
Hope it helps !
Cédric
Here's an example:
class Program
{
public delegate void TestDel();
public static void ToInvoke(TestDel testDel)
{
testDel();
}
public static void Test()
{
Console.WriteLine("hello world");
}
static void Main(string[] args)
{
TestDel testDel = Program.Test;
typeof(Program).InvokeMember(
"ToInvoke",
BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
null,
null,
new object[] { testDel });
}
}
I think this blog post:
C# Reflection - Dealing with Remote Objects
answers your question perfectly.
you can see a delegate as variable type "function". the delegate describes the parameters and return value for a matching function.
delegate void Foo(int a); // here a new delegate obj type Foo has been declared
the above example allows 'Foo' to be used as a data type, the only allowed object that can be matched with a variable of type Foo data type is a method with the same signature so:
void MyFunction(int x);
Foo D = MyFunction; // this is OK
void MyOtherFunction(string x);
Foo D = MyOtherFunction; // will yield an error since not same signature.
Once you have assigned a method to a delegate, you can invoke the method via the delegate:
int n = 1;
D( n ); // or D.Invoke( n );

Categories

Resources