In C# you can do this:
foo = string.Format("{0} {1} {2} {3} ...", "aa", "bb", "cc" ...);
This method Format() accepts infinite parameters, being the first one how the string should be formatted and the rest are values to be put in the string.
Today I've come to a situation where I had to get a set of strings and test them, then I remembered this language functionality, but I had no clue. After a few unsuccessful web searches, I've realised it would be more prudent to just get an array, which didn't make me quite satisfied.
Q: How do I make a function that accepts infinite parameters? And how do I use it ?
With the params keyword.
Here is an example:
public int SumThemAll(params int[] numbers)
{
return numbers.Sum();
}
public void SumThemAllAndPrintInString(string s, params int[] numbers)
{
Console.WriteLine(string.Format(s, SumThemAll(numbers)));
}
public void MyFunction()
{
int result = SumThemAll(2, 3, 4, 42);
SumThemAllAndPrintInString("The result is: {0}", 1, 2, 3);
}
The code shows various things. First of all the argument with the params keyword must always be last (and there can be only one per function). Furthermore, you can call a function that takes a params argument in two ways. The first way is illustrated in the first line of MyFunction where each number is added as a single argument. However, it can also be called with an array as is illustrated in SumThemAllAndPrintInString which calls SumThemAll with the int[] called numbers.
Use the params keyword. Usage:
public void DoSomething(int someValue, params string[] values)
{
foreach (string value in values)
Console.WriteLine(value);
}
The parameter that uses the params keyword always comes at the end.
A few notes.
Params needs to be marked on an array type, like string[] or object[].
The parameter marked w/ params has to be the last argument of your method. Foo(string input1, object[] items) for example.
use the params keyword. For example
static void Main(params string[] args)
{
foreach (string arg in args)
{
Console.WriteLine(arg);
}
}
You can achieve this by using the params keyword.
Little example:
public void AddItems(params string[] items)
{
foreach (string item in items)
{
// Do Your Magic
}
}
public static void TestStrings(params string[] stringsList)
{
foreach (string s in stringsList){ }
// your logic here
}
public string Format(params string[] value)
{
// implementation
}
The params keyword is used
function void MyFunction(string format, params object[] parameters) {
}
Instad of object[] you can use any type your like. The params argument always has to be the last in the line.
Related
C# has a great params keyword for passing arbitary number of arguments to functions such as String.Format(). But what if I need to pass named parameters (key-value pairs)? What is the best method for that (I'm looking for a short syntax on callers side)?
func(new Dictionary<string, object> { { "param1", val1 }, { "param2", val2 } } is too cumbersome
func(param1 => val1, param2 => val2) and func(new { param1 = val1, param2 = val2 }) but it looks like language abuse and those features are not supposed to be used like that
on dynamic objects I can parse optional parameters names func(param1: val1, param2: val2) which looks like a good solution but is doesn't work for common object methods
you can create some overloads of function. when there are only 1 or 2 parameters on caller-side, those overloads will encapsulate usage of Dictionary
public void Foo (string paramA, object valueA)
{
this.Foo(new Dictionary<string, object> { { paramA, valueA } });
}
public void Foo (string paramA, object valueA, string paramB, object valueB)
{
this.Foo(new Dictionary<string, object> { { paramA, valueA },{ paramB, valueB } });
}
public void Foo (Dictionary<string, object> args)
{
}
If.NET Framework 4 is ok for you, maybe you can use Tuple
void MyFunction(params Tuple<string, int>[] p)
// Example of call
MyFunction(Tuple.Create("pipo", 1), Tuple.Create("poil", 2)); // Matthew Mcveigh
[Edit]
An other way is to cast everybody as object:
void MyFunction(params object[] data)
{
for (var i = 0; i < data.Length; i += 2)
{
var s = (string) (data[i]);
var k = (int) (data[i+1]);
...
}
}
...
// Example of call
MyFunction("pipo", 1, "poil", 2);
params can only be used once. And the type of the data passed by it is unique. With params you can either:
Use the generic type object
Use a tuple
There is no way that you can just pass an arbitrary long list of parameters with different type.
If you admit that, for preserving the type, you have to put your stuffs in some new container the cheapest way is to use two of them.
void MyFunction(string[] names, int[] values)
// Example of call
MyFunction(new[] {"pipo", "poil"}, new[] {1, 2});
One example of a library with an API like the one you want to make is iTween. It's well known in some game dev circles, so the practice can't be considered that bad.
It uses a helper function to create a hash table that's passed to the main function. You call it like this:
iTween.MoveTo(camera, iTween.Hash("path", iTweenPath.GetPath("CamPath"), "looktarget", player,
"looktime", 0f, "speed", 2, "easetype", iTween.EaseType.linear));
It's open source, so you can look it if you want to search for "itween.cs". The helper function takes a params object[] args argument list, and makes sure each one is a valid type, then puts it in a Hashtable. Argument name (must be a string), then argument (in your case, this will be an object). The main function will access the arguments as elements of the Hashtable.
It's not type safe at all. But I think it's the only way to do what you're asking for.
public class bar:foo
{
public bar(int something, params object[] parameters)
:base(something, parameters) //foo will receive {int, object[]}, not what i want
{
}
}
public class foo
{
public foo(params object[] parameters)
{
}
}
so basically i would like to append one more object infront of the params array which i pass into the base class. Lets say I call bar(1, 2, 3, 4, 5) i want foo to receive {1, 2, 3, 4, 5} as params instead of {1, {2, 3, 4, 5}} which is what the code above is giving me.
The solution is to create a new array that contains the first element + the elements from the original array, and pass the new array to the other method.
You can do that by creating a new array that holds the first parameter, and using Concat to create a collection containing this parameter and the original array, and then turning that collection back into an array.
This expression would do it:
new object[] { something }.Concat(parameters).ToArray()
Thus your constructor definition would look like this:
public bar(int something, params object[] parameters)
:base(new object[] { something }.Concat(parameters).ToArray())
{
}
Old school:
Create array [N + 1]
Copy the first parameter
Copy/Append the params array, after that.
Sometimes you don't need LINQ, where the size of the arrays is known in this case.
public static T[] Append<T>(this T first, params T[] items)
{
T[] result = new T[items.Length + 1];
result[0] = first;
items.CopyTo(result, 1);
return result;
}
(For very old school use Object instead of T)
I like an extension; bit of both answers so far:
public static class ObjectExtensions
{
public static object[] PrependToParamArray(this object me, params object[] args)
{
return new[] {me}.Concat(args).ToArray();
}
}
Usually arrays are frowned upon. A better solution would use a LinkedList which provides ways for adding front
Édit
If you need to keep the variable parameters then you can use the .Union.ToArray() method available on c# arrays
Is it possible in C# to accept a params argument, then pass it as params list to another function? As it stands, the function below will pass args as a single argument that is an array of type object, if I'm not mistaken. The goal here is self evident.
//ScriptEngine
public object[] Call(string fnName, params object[] args)
{
try{
return lua.GetFunction(fnName).Call(args);
}
catch (Exception ex)
{
Util.Log(LogManager.LogLevel.Error, "Call to Lua failed: "+ex.Message);
}
return null;
}
The lua.GetFunction(fnName).Call(args); is a call to outside of my code, it accepts param object[].
If the signature of the Call method you're calling accepts a params object[] args then you are mistaken. It doesn't consider args a single object of thpe object, to be wrapped in another array. It considers it the entire argument list, which is what you want. It'll work just fine exactly as it stands.
Yes, it is possible.In your case args actualy an array of objects.Your Call method should take params object[] or just an array of objects as parameter.
You don't need to pass more than one argument to params.You can pass an array directly.For example this is completely valid:
public void SomeMethod(params int[] args) { ... }
SomeMethod(new [] { 1, 2, 3 });
It is possible to pass the array to another function:
void Main()
{
int[] input = new int[] {1,2,3};
first(input); //Prints 3
}
public void first(params int[] args)
{
second(args);
}
public void second(params int[] args)
{
Console.WriteLine(args.Length);
}
Suppose I have this method I want to call, and it's from a third-party library so I cannot change its signature:
void PrintNames(params string[] names)
I'm writing this method that needs to call PrintNames:
void MyPrintNames(string[] myNames) {
// How do I call PrintNames with all the strings in myNames as the parameter?
}
I would try
PrintNames(myNames);
You would know if you had a look at the specs on MSDN: http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
They demonstrated it quite clearly - note the comment in the sample code:
// An array argument can be passed, as long as the array
// type matches the parameter type of the method being called.
Sure. The compiler will convert multiple parameters into an array, or just let you pass in an array directly.
public class Test
{
public static void Main()
{
var b = new string[] {"One", "Two", "Three"};
Console.WriteLine(Foo(b)); // Call Foo with an array
Console.WriteLine(Foo("Four", "Five")); // Call Foo with parameters
}
public static int Foo(params string[] test)
{
return test.Length;
}
}
Fiddle
How can I get both these two methods to compile?
public static IEnumerable<string> DoSomething(params string[] args)
{ // do something }
public static IEnumerable<string> DoSomething(this string[] args)
{ // do something }
I get this compile error:
Type 'Extensions' already defines a member called 'DoSomething' with the same parameter types Extensions.cs
So that I can do this:
new string[] { "", "" }.DoSomething();
Extensions.DoSomething("", "");
Without the params method, I have to do this:
Extensions.DoSomething(new string[] { "", "" });
Update: Based on the answer by O. R. Mapper
public static IEnumerable<string> DoSomething(string arg, params string[] args)
{
// args null check is not required
string[] argscopy = new string[args.Length + 1];
argscopy[0] = arg;
Array.Copy(args, 0, argscopy, 1, args.Length);
return argscopy.DoSomething();
}
Update: I like HugoRune's answer now.
You can add an additional parameter to the params version:
public static IEnumerable<string> DoSomething(string firstArg, params string[] moreArgs)
That should be sufficient for the compiler to distinguish it from the string[] extension method.
As suggested by user SLaks, an additional overload without any arguments should be provided in this case, if the situation with an empty params array needs to be supported:
public static IEnumerable<string> DoSomething()
Late answer:
Another option is to just put both methods in different classes. Since you never us the class name when calling the extension method (the one with the this parameter), the extension method can be in any public static class in the same namespace, without any noticeable difference.
// contains static methods to help with strings
public static class StringTools
{
public static IEnumerable<string> DoSomething(params string[] args)
{
// do something
}
}
// contains only extension methods
public static class StringToolsExtensions
{
public static IEnumerable<string> DoSomething(this string[] args)
{
return StringTools.DoSomething(args);
}
}
This way you avoid copying the string array, you do not need an additional overload with no arguments, and I would say it looks cleaner. I would always separate extension methods and other static methods to avoid confusion.
You can give one of the two methods a different name. i.e. DoSomething2
You can just use one method. It's the same method with the same parameter list; clearly they're doing the same thing (since you didn't give them different names as per #1). Just combine them.
You can change the parameter list of one of the methods. i.e. (this string[] args, object unusedParameter)