C# 4.0, optional parameters and params do not work together
Asked Answered
T

3

70

How can i create a method that has optional parameters and params together?

static void Main(string[] args)
{

    TestOptional("A",C: "D", "E");//this will not build
    TestOptional("A",C: "D"); //this does work , but i can only set 1 param
    Console.ReadLine();
}

public static void TestOptional(string A, int B = 0, params string[] C)
{
    Console.WriteLine(A);
    Console.WriteLine(B);
    Console.WriteLine(C.Count());
}   
Trilbee answered 16/10, 2010 at 12:56 Comment(1)
It is a bit unfortunate that one of the answers to this question has been marked as accepted, because there currently is no way to make the optional parameters construct work together with the params construct such that each construct is used as intended. What all answers below are suggesting is workarounds, that fail to use the constructs as intended. The language does not currently offer a proper solution to this problem.Lighter
A
47

Your only option right now is to overload the TestOptional (as you had to do before C# 4). Not preferred, but it cleans up the code at the point of usage.

public static void TestOptional(string A, params string[] C)
{
    TestOptional(A, 0, C);
}

public static void TestOptional(string A, int B, params string[] C)
{
    Console.WriteLine(A);
    Console.WriteLine(B);
    Console.WriteLine(C.Count());
}
Accommodative answered 9/2, 2011 at 20:15 Comment(5)
Yep, this is the only way to accomplish what the OP is asking that I know of. I don't think it's necessarily bad though. Just creates a little more code but it's simple enough to not be confusing.Portiaportico
Also, this doesn't work for Method Caller Information Attributes, such as [CallerMemberName].Timely
It is possible, see my answer belowMot
@CalebJares - katbyte is right, it does work if you use named arguments: #9785130Marney
This is not really an acceptable answer. C# is just behind here, the compiler should be able to interpret void meth(params T[] a, opt b = default(opt)). The call would then look like: meth(a1, a2, a3, ... b: someB); meth(a1, a2, a3); As @CalebJares mentioned this would be useful for being able to invoke methods with hidden parameters. His use case is [CallerMemberName] but this could be for any method with an attribute attached.Myongmyopia
H
17

Try

TestOptional("A", C: new []{ "D", "E"});
Hawfinch answered 16/10, 2010 at 12:58 Comment(3)
that works well for the example. but when i would need a signature like this, i am obligated to specify the type. public static void TestOptional<T>(T A, int B = 0, params Action<T>[] C)Trilbee
@Trilbee so you dont like write similar to: Action<string> test = x => Console.WriteLine(x); Action<string> test2 = y => Console.WriteLine(y); TestOptional("A", C: new [] { test, test2 }); Am I understand correctly or what do you mean?Panegyric
Using your method and the signature i previously commented. The parser needs the type 'new Action<string>[]' ant not just 'new[]'. This results in much 'code-noise' when dealing with expressions of generic types and so on. Example on the simpler signature: TestOptional("A",C: new Action<string>[]{ d=>d.ToString(),d=>d.ToString()});Trilbee
M
16

This worked for me:

    static void Main(string[] args) {

        TestOptional("A");
        TestOptional("A", 1);
        TestOptional("A", 2, "C1", "C2", "C3"); 

        TestOptional("A", B:2); 
        TestOptional("A", C: new [] {"C1", "C2", "C3"}); 

        Console.ReadLine();
    }

    public static void TestOptional(string A, int B = 0, params string[] C) {
        Console.WriteLine("A: " + A);
        Console.WriteLine("B: " + B);
        Console.WriteLine("C: " + C.Length);
        Console.WriteLine();
    }
Mot answered 10/12, 2012 at 19:39 Comment(3)
This doesn't match with the signature the OP has. The 'B' is now a string which can be null. In addition this answer changed 'C' to an object. This is an answer to a different question. Types matter.Accommodative
The question was "How can i create a method that has optional parameters and params together?" and my answer showed how to do so. However yes i used different types because I was trying to accomplish something different. Easy enough to change the types to match.Mot
Yes this will work. It adds the clutter of the new[] { }, which is not exactly how you would want to write this given that most of the time you never have to do that with a params, in fact it is unexpected to have to do that. The OP's question illustrates that the compiler cannot infer a named 'params' parameter using the params syntax at the calling site.Accommodative

© 2022 - 2024 — McMap. All rights reserved.