6

Life is short

def foo(b,a,r):
    # bla bla bla
    pass

mylist = ['b','a','r']
foo(*mylist) 

That's how passing a list of arguments into method multiple positional parameters in Python.

But in C# I found out passing an array into a parameter of array using the params keywords, like this one:

void foo(params string[] bar)
{
    // bla bla bla
}

string[] mylist = {"b", "a", "r"};
foo(mylist)

Imagine how If I cannot touch the function, is there an easier way Is there a way to do that?

Here is what I mean:

void foo (string b, string a, string r)
{
    // bla bla bla
}

string[] mylist = {"b", "a", "r"};
foo(mylist[0],mylist[1],mylist[2]); // This line makes my life difficult

I search online and can't found an alternative of it. Just want to make sure that I didn't miss the hidden feature that C# provide. Who know there's such shortcut for us?

5
  • 1
    If you can't modify the function parameters to accept the params array, then you can't do that. Commented Feb 11, 2012 at 17:25
  • 3
    params would be the solution, ruling that out puts C# at an unfair disadvantage ;-) Commented Feb 11, 2012 at 17:25
  • Well YeoE can you be more specific what you want to achieve ,if it's shortening the parameter list of a method then you have got it right, params is the solution Commented Feb 11, 2012 at 17:29
  • But using params argument, we don't know what argument the method required and how many argument are required. That's why I separate each of the arguments with different variables names so that we know what is the next parameters to pass in. Commented Feb 11, 2012 at 17:54
  • @YeoE, if you have several parameters with different meaning, you should not pass them in an array. Commented Feb 14, 2012 at 14:05

5 Answers 5

3

No, there is no feature in C# that allows you to do this directly. But there are some ways you can use to work around that:

  1. Create a method that converts a method with several parameters into a method with one array parameter:

    static Action<T[]> ToArrayMethod<T>(Action<T, T, T> original)
    {
        return array => original(array[0], array[1], array[2]);
    }
    

    And then use it like this:

    string[] array = {"b", "a", "r"};
    
    var arrayFoo = ToArrayMethod(foo);
    
    arrayFoo(array);
    

    The downside of this approach is that this method works only on methods with exactly three parameters with a void return type. You would need to write another overload of ToArrayMethod() if you wanted this to work for methods with, say, 4 parameters, or for those that return some value.

  2. Use reflection. When doing that, arguments are passed in using an array:

    var foo = typeof(SomeType)
        .GetMethod("foo", BindingFlags.Instance | BindingFlags.NonPublic);
    
    object[] array = {"b", "a", "r"};
    
    foo.Invoke(somTypeInstance, array);
    
Sign up to request clarification or add additional context in comments.

Comments

1

There is downsides to using static languages, and this is one of them, if your function signature is defined as:

void foo (string a, string b, string c);

then you are forced to pass in 3 separate strings

foo(mylist[0],mylist[1],mylist[2]);

the only way to have flexible inputs in C# is by using params which you already now, or by using default values (C# 4.0):

void foo (string a, string b = null, string c = null)

meaning that if I don't pass b or c just set them to null, and now you can call your function like this:

foo(mylist[0]) 

2 Comments

But using params string[] bar, we don't know what argument they required. That's why I separate each of the arguments with variables.
@YeoE Exactly, params has no limit, and won't work in your case unfortunately you either have to change the signature or through an error if the array length is not exactly 3
1

You could use reflection; however, that typically isn’t recommended because it makes you sacrifice compile-time type-safety checking.

Here is a sample approach:

string[] mylist = { "b", "a", "r" };
((Action<string,string,string>)foo).DynamicInvoke(mylist);

1 Comment

Thanks for the note given... I mean the type safety checking :)
0

There is no shortcut. If you want to get crazy and you're able to modify the function somewhat, you could overload it to have one signature with the params keyword, and have the original overload pass its arguments into the the new one.

Comments

0

So to summarize a lot of replies here, you'll need a sort of a hack for this and the cleanest way in my opinion is something along these lines:

Create an extension function for enumerables:

public static class Extensions
{
    public static void SendToMethod<T>(this IEnumerable<T> self, Delegate func  )
    {
        Contract.Requires(func.Method.GetParameters().Length == self.Count());
        func.DynamicInvoke(self.Cast<object>().ToArray());
    }
}

Then you can send the array to any function having an argument count equal to the length of the enumerable:

public void foo(string a, int b, bool c, string d) {}
public void foo2(string a, string b, string c) {}

...
var test1 = new object[] {"ASDF", 10, false, "QWER"};
var test2 = new[] {"A", "B", "C"};

test2.SendToMethod((Action<string, string, string>)foo);
test1.SendToMethod((Action<string, int, bool, string>)foo2); 

1 Comment

Personally, I don't like this because it's "backwards". Something like method.InvokeWithArray(array) makes more sense to me. Also, you can avoid the cast by having overloads for each version of Action.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.