Optional argument followed by Params [duplicate] - c#

This question already has answers here:
C# 4.0, optional parameters and params do not work together
(3 answers)
Closed 9 years ago.
So I see that it's possible to have a method signature where the first parameter provides a default value and the second parameter is a params collection.
What I can't see is a way to actually use the default value of the first argument.
Is it at all possible?
Example method:
void WaitAllTasks(string message = "Running Task.WaitAll", params Task[] tasks);
I initially tried omitting the message parameter when calling the method and also tried using named parameters, which doesn't work with params.
It compiles, but is it possible to use it?

I can find three ways of calling the method without specifying a value for the first parameter:
using System;
class Test
{
static void PrintValues(string title = "Default",
params int[] values)
{
Console.WriteLine("{0}: {1}", title,
string.Join(", ", values));
}
static void Main()
{
// Explicitly specify the argument name and build the array
PrintValues(values: new int[] { 10, 20 });
// Explicitly specify the argument name and provide a single value
PrintValues(values: 10);
// No arguments: default the title, empty array
PrintValues();
}
}
I haven't found a way of specifying multiple values without explicitly building the array though...

Related

C# function with variable number of arguments causes confusion when multiple overloads available

public string GetErrorMessage(params object[] args)
{
return GetErrorMessage("{0} must be less than {1}", args);
}
public string GetErrorMessage(string message, params object[] args)
{
return String.Format(message, args);
}
Here is the call
Console.WriteLine(GetErrorMessage("Ticket Count", 5));
Output
Ticket Count
This means, it invokes the 2nd overload of the method with 2 parameters: message, variable number of object arguments.
Is there a way to force it to invoke first overload rather than second?
The problem you are seeing is caused because the first item in your method call is a string and therefore will alway match the second method call. You can do 1 of the following to get around the problem:
If the order of the args is not important you could simply make sure that the first item is not a string:
this.GetErrorMessage(5, "Ticket Count");
Or you can cast the string to an object:
this.GetErrorMessage((object)"Ticket Count", 5);
You could always make this call however it does break the whole purpose of using params:
this.GetErrorMessage(new object[] {"Ticket Count", 5 });
Console.WriteLine(GetErrorMessage(new object[] { "Ticket Count", 5 }));
No, there is no way to take full advantage of the params keyword for the situation you are describing. The compiler sees a more specific, better fit during overload resolution because of the string argument provided. So the only way to force it into the first form is to explicitly force the string into an object []. Something like this:
Console.WriteLine(GetErrorMessage(new object[] { "Ticket Count", 5 }));

Unable to pass List<char> to List<object> as a parameter? [duplicate]

This question already has answers here:
Why covariance and contravariance do not support value type
(4 answers)
Closed 7 years ago.
So I have a method in my code where one of the parameters is a IEnumerable<object>. For clarity purposes, that will be the only parameter for the example. I was originally calling it with a variable that was a List<string>, but then realized I only needed those to be chars and changed the signature of the variable to List<char>. Then I received an error in my program saying:
Cannot convert source type 'System.Collections.Generic.List<char>'
to target type 'System.Collections.Generic.IEnumerable<object>'.
In code:
// This is the example of my method
private void ConversionExample(IEnumerable<object> objs)
{
...
}
// here is another method that will call this method.
private void OtherMethod()
{
var strings = new List<string>();
// This call works fine
ConversionExample(strings);
var chars = new List<char>();
// This will blow up
ConverstionExample(chars);
}
The only reason that I could possibly think of as to why the first will work, but the second won't is because a List<char>() is convertible to a string? I don't really think that would be it, but that's the only long-shot guess that I can make about why this doesn't work.
Generic argument covariance doesn't support value types; it only works when the generic argument is a reference type.
You can either make ConversionExample generic and accept an IEnumerable<T> rather than an IEnumerable<object>, or use Cast<object> to convert the List<char> to an IEnumerable<object>.
This would be my solution:
// This is the example of my method
private void ConversionExample<T>(IEnumerable<T> objs)
{
...
}
// here is another method that will call this method.
private void OtherMethod()
{
var strings = new List<string>();
// This call works fine
ConversionExample<string>(strings);
var chars = new List<char>();
// This should work now
ConversionExample<char>(chars);
}

Automatically inherit all method signatures when writing a helper method? (C#)

Suppose I'm trying to write a wrapper method around an existing static method. Let's take the console for example.
public static void WriteWithPrefix(string prefix, ...)
{
Console.Write(prefix);
Console.Write(" - ");
// Console.Write(...)
}
The Console.Write method has something like 18 signatures, covering the gamut of primitive types as well as replicating the String.Format methods.
Is there a way to write this helper class such so that it can also accept any of the data types that Console.Write normally accepts?
Another example:
public static void WriteWithTimestamp(...)
{
Console.Write(DateTime.Now.ToString());
Console.Write(": ");
// Console.Write(...)
}
When I call the WriteWithTimestamp method I want to be able to pass it anything that I could also give to Console.Write...
To do this in a normal fashion, you would need to make an overload for each of the Console.Write overloaded functions, which means multiple overloads of your method.
However, you could use dynamic as an alternative approach to accomplish your goals:
public static void WriteWithTimestamp(dynamic value)
{
Console.Write(DateTime.Now.ToString());
Console.Write(": ");
Console.Write(value);
}
Using dynamic will cause it to evaluate and use the most appropriate overload at runtime. Since Console.Write has an overload which accepts object as a parameter, this should never cause an exception, as well.
You have to overload your method and write as many signatures as Console.Write() has with same types of parameters that are accepted by Console.Write()
Or..you can write one method that has all of Console.Write's parameters set to null or to some value like this:
public static void WriteWithTimestamp(string text = null, DateTime date = null, ...)
{
Console.Write(DateTime.Now.ToString());
Console.Write(": ");
// Console.Write(...)
}
Now you can choose which parameters to pass to your method without having to overload it.
Edit: Using dynamic is the better approach, had no idea it existed :-)
In the case of your specific example, I would just expose a WriteWithTimestamp(string) method, and leave it up to the caller to convert their parameters to string using ToString or String.Format calls.
However, assuming you meant to ask the question generally, I would suggest accepting a params object[] array, and passing it to an invocation of your static method resolved through reflection:
public static void Main(string[] args)
{
Console.WriteLine("Location is ({0},{1})", 4, 7);
WriteWithTimestamp("Location is ({0},{1})", 4, 7);
}
public static void WriteWithTimestamp(params object[] parameters)
{
Console.Write(DateTime.Now.ToString());
Console.Write(": ");
var parameterTypes = parameters.Select(p => p.GetType()).ToArray();
var writeLine = typeof(Console).GetMethod("WriteLine", parameterTypes);
writeLine.Invoke(null, parameters);
}

C# reflective method invocation with arbitrary number of parameters [duplicate]

This question already has answers here:
Calling a function using reflection that has a "params" parameter (MethodBase)
(3 answers)
Closed 8 years ago.
Trying to invoke a method with an arbitrary number of parameters:
Type objType = obj.GetType();
MethodInfo method = objType.GetMethod("InvokedMethod");
method.Invoke(obj, new string[] { "param1", "param2" });
The method signature looks like that:
public void InvokedMethod(params string[] args) { ... }
Why I get following Exception:
System.Reflection.TargetParameterCountException (Parameter count mismatch)
The method doesn't accept two parameters, it accepts one parameter that is an array. The compiler will perform a transformation such that a method call of two strings will be transformed into a call of a single array with two values. That transformation won't be done for you when using reflection. You'll need to explicitly create an array and put the two values in it:
method.Invoke(obj, new object[] { new[]{"param1", "param2"} });
Remember that Invoke doesn't accept a single value of that one parameter either. It accepts an array of all parameters. Passing new string[] { "param1", "param2" } to Invoke is telling Invoke that you have two parameters, each of which are strings. You need to wrap your one array parameter in another array so that Invoke sees that you have one parameter that is itself an array.
Try this:
method.Invoke(obj, new object[] {new string[] {"param1", "param2"}});
.Invoke takes an array of arguments that represents the entire signature. in your case the first argument should be an array of strings. So you have to pass in an array of objects with the first element being the array of strings.

method overloading vs optional parameter in C# 4.0 [duplicate]

This question already has answers here:
Should you declare methods using overloads or optional parameters in C# 4.0?
(13 answers)
Closed 9 years ago.
which one is better? at a glance optional parameter seems better (less code, less XML documentation, etc), but why do most MSDN library classes use overloading instead of optional parameters?
Is there any special thing you have to take note when you choose to use optional parameter (or overloading)?
One good use case for 'Optional parameters' in conjunction with 'Named Parameters' in C# 4.0 is that it presents us with an elegant alternative to method overloading where you overload method based on the number of parameters.
For example say you want a method foo to be be called/used like so, foo(), foo(1), foo(1,2), foo(1,2, "hello"). With method overloading you would implement the solution like this,
///Base foo method
public void DoFoo(int a, long b, string c)
{
//Do something
}
/// Foo with 2 params only
public void DoFoo(int a, long b)
{
/// ....
DoFoo(a, b, "Hello");
}
public void DoFoo(int a)
{
///....
DoFoo(a, 23, "Hello");
}
.....
With optional parameters in C# 4.0 you would implement the use case like the following,
public void DoFoo(int a = 10, long b = 23, string c = "Hello")
Then you could use the method like so - Note the use of named parameter -
DoFoo(c:"Hello There, John Doe")
This call takes parameter a value as 10 and parameter b as 23.
Another variant of this call - notice you don't need to set the parameter values in the order as they appear in the method signature, the named parameter makes the value explicit.
DoFoo(c:"hello again", a:100)
Another benefit of using named parameter is that it greatly enhances readability and thus code maintenance of optional parameter methods.
Note how one method pretty much makes redundant having to define 3 or more methods in method overloading. This I have found is a good use case for using optional parameter in conjunction with named parameters.
Optional Parameters provide issues when you expose them publicly as API. A rename of a parameter can lead to issues. Changing the default value leads to issues (See e.g. here for some info: Caveats of C# 4.0 optional parameters)
Also, optional params can only be used for compile-time constants. Compare this:
public static void Foo(IEnumerable<string> items = new List<string>()) {}
// Default parameter value for 'items' must be a compile-time constant
to this
public static void Foo() { Foo(new List<string>());}
public static void Foo(IEnumerable<string> items) {}
//all good
Update
Here's some additional reading material when a constructor with default parameters does not play nicely with Reflection.
I believe they serve different purposes. Optional parameters are for when you can use a default value for a parameter, and the underlying code will be the same:
public CreditScore CheckCredit(
bool useHistoricalData = false,
bool useStrongHeuristics = true) {
// ...
}
Method overloads are for when you have mutually-exclusive (subsets of) parameters. That normally means that you need to preprocess some parameters, or that you have different code altogether for the different "versions" of your method (note that even in this case, some parameters can be shared, that's why I mentioned "subsets" above):
public void SendSurvey(IList<Customer> customers, int surveyKey) {
// will loop and call the other one
}
public void SendSurvey(Customer customer, int surveyKey) {
...
}
(I wrote about this some time ago here)
This one almost goes without saying, but:
Not all languages support optional parameters. If you want your libraries to be friendly to those languages, you have to use overloads.
Granted, this isn't even an issue for most shops. But you can bet it's why Microsoft doesn't use optional parameters in the Base Class Library.
Neither is definitively "better" than the other. They both have their place in writing good code. Optional parameters should be used if the parameters can have a default value. Method overloading should be used when the difference in signature goes beyond not defining parameters that could have default values (such as that the behavior differs depending on which parameters are passed, and which are left to the default).
// this is a good candidate for optional parameters
public void DoSomething(int requiredThing, int nextThing = 12, int lastThing = 0)
// this is not, because it should be one or the other, but not both
public void DoSomething(Stream streamData = null, string stringData = null)
// these are good candidates for overloading
public void DoSomething(Stream data)
public void DoSomething(string data)
// these are no longer good candidates for overloading
public void DoSomething(int firstThing)
{
DoSomething(firstThing, 12);
}
public void DoSomething(int firstThing, int nextThing)
{
DoSomething(firstThing, nextThing, 0);
}
public void DoSomething(int firstThing, int nextThing, int lastThing)
{
...
}
Optional parameters has to be last. So you can not add an extra parameter to that method unless its also optional. Ex:
void MyMethod(int value, int otherValue = 0);
If you want to add a new parameter to this method without overloading it has to be optional. Like this
void MyMethod(int value, int otherValue = 0, int newParam = 0);
If it can't be optional, then you have to use overloading and remove the optional value for 'otherValue'. Like this:
void MyMethod(int value, int otherValue = 0);
void MyMethod(int value, int otherValue, int newParam);
I assume that you want to keep the ordering of the parameters the same.
So using optional parameters reduces the number of methods you need to have in your class, but is limited in that they need to be last.
Update
When calling methods with optional parameters, you can used named parameters like this:
void MyMethod(int value, int otherValue = 0, int newValue = 0);
MyMethod(10, newValue: 10); // Here I omitted the otherValue parameter that defaults to 0
So optional parameters gives the caller more possibilities.
One last thing. If you use method overloading with one implementation, like this:
void MyMethod(int value, int otherValue)
{
// Do the work
}
void MyMethod(int value)
{
MyMethod(value, 0); // Do the defaulting by method overloading
}
Then when calling 'MyMethod' like this:
MyMethod(100);
Will result in 2 method calls. But if you use optional parameters there is only one implementation of 'MyMethod' and hence, only one method call.
What about a 3rd option: pass an instance of a class with properties corresponding to various "optional parameters".
This provides the same benefit as named and optional parameters, but I feel that this is often much clearer. It gives you an opportunity to logically group parameters if necessary (i.e. with composition) and encapsulate some basic validation as well.
Also, if you expect clients that consume your methods to do any kind of metaprogramming (such as building linq expressions involving your methods), I think that keeping the method signature simple has its advantages.
A good place to use optional parameter is WCF since it does not support method overloading.
This is not really an answer to the original question, but rather a comment on #NileshGule's answer, but:
a) I don't have enough reputation points to comment
b) Multiple lines of code is quite hard to read in comments
Nilesh Gule wrote:
One benefit of using optional parameters is that you need not have to do a conditional check in your methods like if a string was null or empty if one of the input parameter was a string. As there would be a default value assigned to the optional parameter, the defensive coding will be reduced to a great extent.
This is actually incorrect, you still have to check for nulls:
void DoSomething(string value = "") // Unfortunately string.Empty is not a compile-time constant and cannot be used as default value
{
if(value == null)
throw new ArgumentNullException();
}
DoSomething(); // OK, will use default value of ""
DoSomething(null); // Will throw
If you supply a null string reference, it will not be replaced by the default value. So you still need to check the input parameters for nulls.
To address your first question,
why do most MSDN library classes use
overloading instead of optional
parameters?
It is for backward compatibility.
When you open a C# 2, 3.0 or 3.5 project in VS2010, it is automatically upgraded.
Just imagine the inconvenience it would create if each of the overloads used in the project had to be converted to match the corresponding optional parameter declaration.
Besides, as the saying goes, "why fix what is not broken?". It is not necessary to replace overloads that already work with new implementations.
One benefit of using optional parameters is that you need not have to do a conditional check in your methods like if a string was null or empty if one of the input parameter was a string. As there would be a default value assigned to the optional parameter, the defensive coding will be reduced to a great extent.
Named parameters give the flexibility of passing parameter values in any order.

Categories

Resources