Defining functions which can take a lot of parameters in C# - c#

For example, printf in c can take any number of parameters like printf("%d %d %s %s...",a,b,c,d,...) and is documented as below
printf( const char *format [, argument]... );
How can I define such functions in C#?

Using the params keyword:
void WriteAll(params object[] args) {
for(int i = 0; i < args.Length; i++)
Console.WriteLine(args[i]);
}
args will be an array with all the arguments you pass. Note that it must be the last formal argument.

use params object[] arg as the last argument.
http://msdn.microsoft.com/en-us/library/w5zay9db%28v=vs.71%29.aspx
see for more detail

private void Print(params object[] values)
{
foreach (var item in values)
{
Console.WriteLine(item);
}
}
this code will print to the console every item you'll send at the object array using the "params" keyword. you can call this method with as many parameters you like (or none).
link:
http://msdn.microsoft.com/en-us/library/w5zay9db(v=vs.110).aspx

in c# the you'll use the params key word.
public static void UseParams2(params object[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}

Just pass an object with your parameters
private void MyVoid(MyParameterObject params)
{
}

There are several approaches in this case:
You can define a type that holds all fields you need to pass and return between methods. Better then simple object array, cause it's typesafe.
You can define dictionary where place parameter names and values. Better then simple object array, cause it's typesafe.
(This depends on quantity of the parameters, and on use logic of the code) You can define overrloads of the same function.
func A (AA aa)
func A(AA aa, BB bb =null)
func A(AA aa, BB bb = null, CC cc = null)
and so on...

Related

what does this use of delegate mean?

I can't understand why delegate is used here:
List<string> temp_list = new List<string>();
string[] temp_array;
temp_array = Array.ConvertAll(arr_DL[m], delegate (int j) { return j.ToString(); });
temp_list.AddRange(temp_array.ToList());
the code is supposed to convert the array to list.
Can someone help explain the use of delegate here?
That because it's the second parameter of ConvertAll method. It represent how each element in initial Array should be converted:
A Converter<TInput, TOutput> that converts each element from one type to another type.
So your delegate sais "convert each int j to string by performing j.ToString();"
This part:
delegate (int j) { return j.ToString(); }
creates so-called "anonymous method" as second parameter TOutput, which used to convert int variable input into String then passes it into Array.ConvertAll() method. Anonymous methods used widely on C# 2.0, where in C# 3.0 they substituted with lambda expression like this:
delegate String output (int j);
String output = x => { x.ToString(); }
Reference: https://msdn.microsoft.com/en-us/library/bb882516.aspx
CMIIW.

Having two param lists with same size

The method PrintTimes(string a, int b) prints the string a, b times (i.e. PrintTimes("test",3) will print testtesttest).
I want to create a method, which will get a params array of strings and a params array of integers. So the call function will ook like this
PrintTimes("A","B","C","D",2,1,3,2);
Or
PrintTimes("A",2,"B",1,"C",3,"D",2)
Both of which will print AABCCCDD
Since there can be only one params parameter in a method, this is impossible. So is there a way to do this?
I know I can create a Class with a string and an int variable, and create a params array for the class. But I'd rather not, since it would involve constructing a new Class for each set
Why not using a class
public class PrintParameter
{
public int Count {get;set;}
public string Content{get;set;}
}
Then
public void PrintTimes(List<PrintParameter> inputs)
{
//for each input print the "Content", "Count" times
}
Or
public void PrintTimes(params PrintParameter[] inputs)
{
//for each input print the "Content", "Count" times
}
If you don't want to define a class you may try something like List<KeyValuePair<string,int>> or other alternatives such as List<Tuple<string,int>> and etc. However the preferred way of doing is to use a class with meaningful properties.
How about just dropping the params keyword and taking arrays instead? That is, make the signature PrintTimes(string[], int[]). PrintTimes(new[]{"A","B","C","D"}, new[]{2,1,3,2}); isn't that much more to write.
There are several ways you can go about solving this problem. While you can only have one params, you can just make both your parameters arrays:
PrintTimes(string[] strings, int[] printCounts)
{
// Assert strings.Length == printCounts.Length
for (int i = 0; i < strings.Length; i++)
{
for (int j = 0; j < printCounts[i]; j++)
{
// Print strings[i]
}
}
}
Then it can be called like this:
int[] numbers = new int[3] {1, 2, 3};
string[] names = new string[3] {"Matt", "Joanne", "Robert"};
PrintTimes(names, numbers);
Following up on Hossein's suggestion, why not something as simple as:
void PrintTimes(List<String> strings, List<Int> count)
(or do it as an array as the comments said) Then inside PrintTimes require the inputs to be the same length or some logical fail when they don't.

Function with variable number of arguments

As the title says I need to know if there is a corresponding syntax as java's ... in method parameters, like
void printReport(String header, int... numbers) { //numbers represents varargs
System.out.println(header);
for (int num : numbers) {
System.out.println(num);
}
}
(code courtesy of wikipedia)
Yes you can write something like this:
void PrintReport(string header, params int[] numbers)
{
Console.WriteLine(header);
foreach (int number in numbers)
Console.WriteLine(number);
}
Try using the params keyword, placed before the statement, eg
myFunction(params int[] numbers);
Yes, there is. As Adriano said you can use C# 'params' keyword.
An example is the in link below:
params (C# Reference)
http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
"The params keyword lets you specify a method parameter that takes a variable number of arguments.
You can send a comma-separated list of arguments of the type specified in the parameter declaration, or an array of arguments of the specified type. You also can send no arguments.
No additional parameters are permitted after the params keyword in a method declaration, and only one params keyword is permitted in a method declaration."
You can declare a method to har a variable number of parameters by using the params keyword. Just like when using ... in Java, this will give you an array and let you call the metods with a variable number of parameters:
http://msdn.microsoft.com/en-us/library/w5zay9db(v=vs.71).aspx
This should be
void printReport(String header, params int[] numbers)
I believe you mean params
public void printReport(string header, params int[] list)
{
Console.WriteLine(header);
for (int i = 0 ; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
You can use params, although this must always come last in the list:
public void PrintReport(string header, params int[] numbers)
{
It is however possible to combine params optional parameters (such as [CallerMemberName]) by using named arguments, which works even if the parameters are of the same type.
Declare the method like this:
public static void PrintReport(
[CallerMemberName] string callerName = "",
[CallerFilePath] string sourceFilePath = "",
params string[] inputStrings)
{
and call it like this:
PrintReport(inputStrings: new[] { "string 1", "string 2" } );

Does C# support a variable number of arguments, and how?

Does C# support a variable number of arguments?
If yes, How does C# support variable no of arguments?
What are the examples?
How are variable arguments useful?
EDIT 1: What are the restrictions on it?
EDIT 2: The Question is not about Optional param But Variable Param
Yes. The classic example wourld be the params object[] args:
//Allows to pass in any number and types of parameters
public static void Program(params object[] args)
A typical usecase would be passing parameters in a command line environment to a program, where you pass them in as strings. The program has then to validate and assign them correctly.
Restrictions:
Only one params keyword is permitted per method
It has to be the last parameter.
EDIT: After I read your edits, I made mine. The part below also covers methods to achieve variable numbers of arguments, but I think you really were looking for the params way.
Also one of the more classic ones, is called method overloading. You've probably used them already a lot:
//both methods have the same name and depending on wether you pass in a parameter
//or not, the first or the second is used.
public static void SayHello() {
Console.WriteLine("Hello");
}
public static void SayHello(string message) {
Console.WriteLine(message);
}
Last but not least the most exiting one: Optional Arguments
//this time we specify a default value for the parameter message
//you now can call both, the method with parameter and the method without.
public static void SayHello(string message = "Hello") {
Console.WriteLine(message);
}
http://msdn.microsoft.com/en-us/library/dd264739.aspx
C# supports variable length parameter arrays using the params keyword.
Here's an example.
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}
There's more info here.
Yes, params:
public void SomeMethod(params object[] args)
params has to be the last argument and can be of any type. Not sure if it has to be an array or just an IEnumerable.
I assume you mean a variable number of method parameters. If so:
void DoSomething(params double[] parms)
(Or mixed with fixed parameters)
void DoSomething(string param1, int param2, params double[] otherParams)
Restrictions:
They must all be the same type (or of a child type) as is true for arrays as well
There can only be one for each method
They must come last in the parameter list
That's all I can think of at the moment though there could be others. Check the documentation for more information.

Can an Action/delegate change it's arguments value?

I ran into what was to me an unexpected result when testing a simple ForEach extension method.
ForEach method
public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
if (action == null) throw new ArgumentNullException("action");
foreach (T element in list)
{
action(element);
}
}
Test method
[TestMethod]
public void BasicForEachTest()
{
int[] numbers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
numbers.ForEach(num =>
{
num = 0;
});
Assert.AreEqual(0, numbers.Sum());
}
Why would numbers.Sum() be equal to 55 and not 0?
num is the copy of the value of the current element you are iterating over. So you are just changing the copy.
What you do is basically this:
foreach(int num in numbers)
{
num = 0;
}
Surely you do not expect this to change the content of the array?
Edit: What you want is this:
for (int i in numbers.Length)
{
numbers[i] = 0;
}
In your specific case you could maintain an index in your ForEach extension method and pass that as second argument to the action and then use it like this:
numbers.ForEachWithIndex((num, index) => numbers[index] = 0);
However in general: Creating Linq style extension methods which modify the collection they are applied to are bad style (IMO). If you write an extension method which cannot be applied to an IEnumerable<T> you should really think hard about it if you really need it (especially when you write with the intention of modifying the collection). You have not much to gain but much to loose (like unexpected side effects). I'm sure there are exceptions but I stick to that rule and it has served me well.
Because num is a copy.
It's as if you were doing this:
int i = numbers[0];
i = 0;
You wouldn't expect that to change numbers[0], would you?
Because int is a value type and is passed to your extension method as a value parameter. Thus a copy of numbers is passed to your ForEach method. The values stored in the numbers array that is initialized in the BasicForEachTest method are never modified.
Check this article by Jon Skeet to read more on value types and value parameters.
I am not claiming that the code in this answer is useful, but (it works and) I think it illustrates what you need in order to make your approach work. The argument must be marked ref. The BCL does not have a delegate type with ref, so just write your own (not inside any class):
public delegate void MyActionRef<T>(ref T arg);
With that, your method becomes:
public static void ForEach2<T>(this T[] list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Length; idx++)
{
actionRef(ref list[idx]);
}
}
Now, remember to use the ref keyword in your test method:
numbers.ForEach2((ref int num) =>
{
num = 0;
});
This works because it is OK to pass an array entry ByRef (ref).
If you want to extend IList<> instead, you have to do:
public static void ForEach3<T>(this IList<T> list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Count; idx++)
{
var temp = list[idx];
actionRef(ref temp);
list[idx] = temp;
}
}
Hope this helps your understanding.
Note: I had to use for loops. In C#, in foreach (var x in Yyyy) { /* ... */ }, it is not allowed to assign to x (which includes passing x ByRef (with ref or out)) inside the loop body.

Categories