void Foo(int a = 1, int b = 2, int c = 3)
in C# you need to write 4 overloads:
void Foo(int a, int b, int c) { ... do stuff ...}
void Foo(int a, int b) : Foo(a,b,3) {}
void Foo(int a) : Foo(a,2,3) {}
void Foo() : Foo(1,2,3) {}
very frustrating!!
Presumably a design decision and one with merit IMO. While default args may
seem convenient, they are less efficient than an equivalent overload and
certainly less clear to read (should we guess that a default arg may be
passed without consulting the docs). It's also more error prone when you
leave out some arguments by accident or ignorance (the default kicks in and
it may not be what you want).
For your specific example, I would do
void Foo(params int[] intVals) { ... do stuff ... }
And then you could call it with
Foo();
Foo(1);
Foo(1, 2);
Foo(1, 2, 3)
or even
Foo(new int[4] {1, 2, 3, 4});
-chris
--
Chris J. Breisch, MCSD.NET, MCDBA
C++ has rules on how overloads work, and because of those rules
people write horrific code that doesn't read easily. Since only
the trailing arguments can have defaults, you end up with things
like this:
void AlertBox(char *text,HWND parent=NULL,int length=-1)
{...}
The idea here is to display a string in a message box. Since
virtually nobody will specify the length of the string, the
sentinel value of -1 is placed all the way at the end so the
function knows to use strlen() to get the length of the string.
The HWND, on the other hand, will be specified in a significant
number of cases -- so it has to come *before* the length to
allow a developer the option of specifying it without the
length. While the string and its length logically *belong* next
to each other, they end up separated and make the code less
readable simply because the language demands that things work
this way.
In C#, you can declare this much more sensibly:
void AlertBox(HWND parent, string text, int length) {...}
void AlertBox(string text, int length):
AlertBox(NULL,text,length) {}
void AlertBox(HWND parent, string text):
AlertBox(parent,text,-1) {}
void AlertBox(string text): AlertBox(NULL,text,-1) {}
I know which set of overloads *I'd* rather have to remember when
I was writing to someone else's API.
No, it's not. Those C++ style overloads create versioning problems. Suppose
that you write a method with a default parameter:
void Foo(int a = 1)
{
}
Now suppose that someone calls that method with a convention that requires
that the default parameter kicks in:
void DoSomething()
{
Foo();
}
The compiler will write IL that will pass in 1 as the parameter to Foo(); in
other words, the compiler will generate IL equivalent to the following:
void DoSomething()
{
Foo(1);
}
The important thing to note here is the value of that default parameter is
"hardcoded" into the caller's executable.
Now, then ... what happens if Foo() and DoSomething() are in separate
assemblies, and, somewhere down the line, the implementation of Foo()
changes the value of your default parameter, as in:
void Foo(int a = 5)
{
}
What will happen to your client code, originally written as follows:
void DoSomething()
{
Foo();
}
Well, Foo() will still be called with a parameter of 1, since that was the
default value when the client code was compiled. But -- wait -- the assembly
with Foo() has been recompiled with a default value of 5? Do you really want
the 1 or the 5? Who knows? Oh, versioning issue! You'll have to recompile
and redeploy the client just to get the right value back into the IL.
Note that C# goes for readability over terseness. If less typing introduces
a potential ambiguity, then C# won't do it. Code that explicitly defines all
parameters during a call is more readable and doesn't suffer from versioning
issues.
--
Jeff Ferguson
Magenic
http://staff.magenic.com/jefff/
Remi
"Jeff Ferguson" <Je...@magenic.com> wrote in message
news:uGc8kRi#CHA....@TK2MSFTNGP11.phx.gbl...