Methods: params string[] with one parameter and single string - c#

This comes from this other question:
( How to build a method with unspecified amount of params en C# ).
But since it's a different question I had to ask it here
Supposing you have a method overloaded (this overload is allowed by the compiler):
private static string AddURISlash(params string[] remotePaths) //multiple strings
private static string AddURISlash(string remotePaths) //single string
How should you know which will be executed when only one parameter is recieved?
Is there a convention? or something that you have to test once?
Do I have to assume that since the only way to the single string method to be executed is to recieve a single string, that's the one that unequivocally be executed?
Thanks

How should you know which will be executed when only one parameter is recieved?
You read the specification, which explains how overload resolution is handled. From section 7.5.3.2, the relevant bullet point is:
Otherwise, if MP is applicable in its normal form and MQ has a params array and is applicable only in its expanded form, then MP is better than MQ.
So the version which doesn't require parameter array expansion (your single string version) is chosen at compile-time instead of the parameter array version.

Related

The type 'T' cannot be used as type parameter 'T' in the generic type or method but it should not use generic method [duplicate]

I have two overloaded methods, one with an optional parameter.
void foo(string a) { }
void foo(string a, int b = 0) { }
now I call:
foo("abc");
interestingly the first overload is called.
why not the second overload with optional value set to zero?
To be honest, I would have expect the compiler to bring an error, at least a warning to avoid unintentional execution of the wrong method.
What's the reason for this behaviour? Why did the C# team define it that way?
From MSDN:
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.
An overload which doesn't require any optional parameters to be filled in automatically is preferred to one which does. However, there's no such preference between filling in one argument automatically and filling in more than one - so for example, this will cause a compile-time error:
void Foo(int x, int y = 0, int z = 0) {}
void Foo(int x, int y = 0) {}
...
Foo(5);
Note that Foo(5, 5) would be resolved to the second method, because then it doesn't require any optional parameters to be automatically filled in.
From section 7.5.3.2 of the C# 4 spec:
Otherwise if all parameters of MP have
a corresponding argument whereas
default arguments need to be
substituted for at least one optional
parameter in MQ then MP is better than
MQ.
I think in most cases this is the behaviour most people would expect, to be honest. It gets weird when you introduce base class methods into the mix, but that's always been the case.
Just imagine if it were the opposite. You had an application. It had a method:
void foo(string a) { }
Everyting worked fine. Now, you want to add one more overload with an optional parameter:
void foo(string a, int b = 0) { }
Boom! All method calls go to the new method. Whenever you want it or not. Adding a method overload might cause wrong method calls all over the application.
From my perspective, in this case you'd have much more opporunities to break your (or someone else's) code.
Also, OptionalAttribute was ignored in C# until version 4.0, but you could use it. And some people did use it in C# code to support certain interoperability scenarios with other languages, such as Visual Basic, or for COM interop. Now C# uses it for optional parameters. Adding warnings/errors may introduce a breaking change for those applications.
There might be some other reasons, but this is just what comes to my mind first.

Can I pass a method as a parameter?

I am developing several plugin methods that generate a string, and pass it back to my main method. From here, I can then come up with a sequence number. However, I want to avoid integrating the plugin into my main program - basically anything that forces me to change my main program in any way to recognise this plugin is off-limits.
So - in my main program, I generate a string, then match it with other matching strings to figure out the sequence number. The trouble is that I need to know the format of this string so I know where to input this number.
I was thinking about possibly passing in a method that knows the matching functions for this string, but I'm not sure how I can pass a method from one program to another.
I have found this question, but this only appears to be within the same program.
In C#, you can either pass a method as the argument of another method provided that it returns something which the recipient method is expecting. Thus, given this:
public int Foo(){ ... }
public void Bar(int i) { ... }
You can do something like so: ...Bar(this.Foo());
However, I think that what you are after actually are delegates, which are essentially function pointers. This would allow you to call the method to which the delegate points to from some other method.
As a side note, you could consider looking into the Strategy Design Pattern. This pattern allows you to essentially determine which behaviour (logic) to call at run time.
First of all for your case you dont need to pass the method. You can make the method public and access in another program in same namespace like:- ClassObject.Method();... here object should be of class where your method is defined
You can Contain the Return value of function as a parameter while calling if thats what you are trying(like:- testapp(Square(x)) if the type of param is same as of method's Return Type .. In another Case Delegates could be useful.

Overloading Methods Or Not?

What I have here are two methods (killZombie) that handle cases where you have one argument (string) or more than one argument (string[]). Because they do the same thing, I made another method named "killAZombie" that is used by the other two methods. The problem I'm having is that the method "killAZombie" is named... well kind of strangely. Is this a problem that other people encounter too? What is the best way to solve this and name my "KillAZombie" method something else that distinguishes itself more clearly from "killZombie"
public void killZombie(string zombieLocation){
killAZombie(zombieLocation);
}
public void killZombie(string[] zombieLocations){
foreach(string zombieLocation in zombieLocations){
killAZombie(zombieLocation);
}
}
public void killAZombie(string zombieLocation){
//Kills a zombie at specified location
}
Another way I can see this problem being solved is by instead of overloading "killZombie" have two different methods like this:
public void killZombie(string zombieLocation){
//Kills a zombie at specified location
}
public void killZombies(string[] zombieLocations){
foreach(string zombieLocation in zombieLocations){
killZombie(zombieLocation);
}
}
This way we only have two methods that are easier to understand, but then the method isn't overloaded. In my mind, it seems like a good thing to have overloaded methods (this just means there are fewer methods, less clutter) so I'm not sure about this solution either. I'd be interested in hearing what would be the best way to tackle this problem, thanks!
Addendum:
My method actually takes 4 arguments, so the params will be at the end. The params variable is the most important one, so putting it as the last argument to make the params work seems kind of clunky. Is my concern over putting the most important argument last, legitimate enough to split up the methods into KillZombie and KillZombies or is the params still the right way to do things?
Here are some ideas.
First, the C# convention for public methods is to capitalize them: "KillZombie", not "killZombie".
You can do this with just one method if you want. Here's a method that takes one or more locations. The caller can just provide a list: KillZombies(location1, location2, location3);
private void KillOneZombie(string location) { ... }
public void KillZombies(string location, params string[] additionalLocations)
{
KillOneZombie(location);
if (additionalLocations == null) return;
foreach(string additionalLocation in additionalLocations)
KillOneZombie(additionalLocation);
}
If you do want to have two methods, consider having one take an IEnumerable<string> instead of an array; that way the caller can pass in a list, a query, an array, whatever.
Your second naming pattern is more standard: KillZombie and KillZombies.
The params variable is the most important one, so putting it as the last argument to make the params work seems kind of clunky. Is my concern over putting the most important argument last, legitimate enough to split up the methods into KillZombie and KillZombies or is the params still the right way to do things?
I would think about how you expect the method to be used. Consider for example:
Console.WriteLine("User: {0} Score: {1}", user[i].Name, scores[i]);
Here we clearly expect that the "params" will be used to support a variable number of arguments in the caller. No one ever does this:
object[] results = new object[] { user[i].Name, scores[i] };
Console.WriteLine("User: {0} Score: {1}", results);
even though that is perfectly legal. If you expect that your method is going to be used like Console.WriteLine, where a varying number of parameters is going to be passed in but the number of parameters is known at compile time, then use params.
If you expect that it is going to be used with the second pattern -- someone has an array of locations -- then do not use params; make two methods, KillZombie and KillZombies, and have one of them take an IEnumerable of strings.
The latter of your two choices is probably preferable in this case (given that the naming of the function implies that it's operating upon a single "zombie".
However, you might also want to look into the params keyword, just so you know what your options are. For instance, if you'd named your function simply Kill (and if it made sense to do so in this context), you could have:
public void Kill(params string[] zombieNames)
{
foreach(string name in zombieNames)
{
}
}
And you could call it a number of ways:
Kill("Zoey");
Kill("Francis", "Zoey");
string[] survivors = { "Zoey", "Francis", "Bill", "Louis" };
Kill(names);
(Assuming, of course, that your survivors had all been turned into zombies!)
Also, stylistically C# code generally uses pascal casing for function names (KillAZombie rather than killAZombie).
Edit for Addendum
Yes, parameter ordering--while it has no technical relevance--is an important consideration in API design, so if you're going to be taking "less important" parameters, then you'll probably have to do without params.
With that said, I'll stand by my original recommendation: as the function is named (KillZombie versus Kill), I would stick with two versions just for the sake of making your name consistent with the parameters. I would also suggest allowing the user to specify IEnumerable<string> instead of an array. That will allow the developer to pass the names using anything that implements IEnumerable<string>, including a string array.
In this case I'd probably go with your second suggestion. KillZombie kills a single zombie; KillZombies kills multiple zombies.
Another option would be to use a single method with a params argument:
KillZombies("foo"); // kill a single zombie
KillZombies("foo", "bar"); // kill multiple zombies
// ...
public void KillZombies(params string[] zombieLocations)
{
foreach (string zombieLocation in zombieLocations)
{
// kills a zombie at specified location
}
}
(Note also that standard C# naming convention would be to use KillZombie/KillZombies with an uppercase "K".)
First of all, there are more than just those two alternatives.
In particular, you can use the first method without the extra method.
public void KillZombie(string zombieLocation){
// Implement zombie killing logic here.
}
public void KillZombie(string[] zombieLocations){
foreach(string zombieLocation in zombieLocations)
KillZombie(zombieLocation);
}
But in this case I would recommend having two different methods. Granted, they do similar things but one takes zombies and one takes a single zombie. The method name should reflect this.
Analogously, the .NET List class has similar methods Add and AddRange.
Your example is sadly wrong - you could also use a params array to allow calls like
KillZombies(location1, location2, location3). Params arrays allow an underterminedn umber of aprameters.
That said, it often is done for easier use. If you have 3 ovterloads beause they are all used, then there is nothing wrong with having them, or?
Look at the differentString.Format methods.
what about using this :
public void killZombies(string zombieLocation, params string[] zombieLocations){
killZombie(zombieLocation);
if(zombieLocations != null) {
foreach(string zombieLocation in zombieLocations){
killZombie(zombieLocation);
}
}
}
You can pass either one or several zombies.
[edit] as commented, this update disallow killing no zombie

C# params keyword with two parameters of the same type

I just encountered something with C# today that I hadn't thought of before. I have two methods in my class, one an overload of the other. They are declared like so:
public void RequirePermissions(params string[] permissions)...
public void RequirePermissions(string message, params string[] permissions)...
In my code, I tried to call the first one like so:
RequirePermissions("Permission1", "Permission2");
...expecting it to call the first overload. Well it called the second overload. The only way I can get it to call the first method in this case is to manually pass a string[] object like so:
RequirePermissions(new string[] { "Permission1", "Permission2" });
Now, this behavior doesn't confuse me because I understand that the compiler can't tell which method I actually wanted to call based on my provided parameters. But was I not careful this could have gone unnoticed in my code. It seems as though Microsoft should have made the compiler throw an error when it encountered a situation like above. Does anyone have any thoughts on this? Is there another way to call the first overload other than the "solution" I posted?
Agreeing with Adam, I'd change it to something like:
public void RequirePermissions(params string[] permissions)
public void RequirePermissionsWithMessage(string message, params string[] permissions)
Personally, I'd do it this way:
public void RequirePermissions(params string[] permissions)...
public void RequireMessageAndPermissions(string message,
params string[] permissions)...
People fall too in love with overloading sometimes, and when you combine that with a love for the params keyword, you just increase the confusion level for whomever eventually has to take over your code.
It looks like there is no other way.
You can find explanation to this behaviour in C# spec http://www.jaggersoft.com/csharp_standard /17.5.1.4.htm and here http://www.jaggersoft.com/csharp_standard/14.4.2.1.htm (paragraph 2)
a parameter array is precisely equivalent to a value parameter (§17.5.1.1) of the same type.
and
The expanded form of a method is available only if the normal form of the method is not
applicable and only if a method with the same signature as the expanded form is not already
declared in the same type
Yes, I agree it should probably be a warning when using variable length argument arrays causes an ambiguous overload - it's very much an edge case, and people almost certainly don't mean to create such situations.
I also don't know of any way, other than that you posted, to avoid the call resolution that occurs - other than to avoid doing it in the first place, which I would highly recommend!
You could not use params and be explicit with your signatures.
public void RequirePermissions(string[] permissions)...
public void RequirePermissions(string message, string[] permissions)..

Should you declare methods using overloads or optional parameters in C# 4.0?

I was watching Anders' talk about C# 4.0 and sneak preview of C# 5.0, and it got me thinking about when optional parameters are available in C# what is going to be the recommended way to declare methods that do not need all parameters specified?
For example something like the FileStream class has about fifteen different constructors which can be divided into logical 'families' e.g. the ones below from a string, the ones from an IntPtr and the ones from a SafeFileHandle.
FileStream(string,FileMode);
FileStream(string,FileMode,FileAccess);
FileStream(string,FileMode,FileAccess,FileShare);
FileStream(string,FileMode,FileAccess,FileShare,int);
FileStream(string,FileMode,FileAccess,FileShare,int,bool);
It seems to me that this type of pattern could be simplified by having three constructors instead, and using optional parameters for the ones that can be defaulted, which would make the different families of constructors more distinct [note: I know this change will not be made in the BCL, I'm talking hypothetically for this type of situation].
What do you think? From C# 4.0 will it make more sense to make closely related groups of constructors and methods a single method with optional parameters, or is there a good reason to stick with the traditional many-overload mechanism?
I'd consider the following:
Do you need your code to be used from languages which don't support optional parameters? If so, consider including the overloads.
Do you have any members on your team who violently oppose optional parameters? (Sometimes it's easier to live with a decision you don't like than to argue the case.)
Are you confident that your defaults won't change between builds of your code, or if they might, will your callers be okay with that?
I haven't checked how the defaults are going to work, but I'd assume that the default values will be baked into the calling code, much the same as references to const fields. That's usually okay - changes to a default value are pretty significant anyway - but those are the things to consider.
When a method overload normally performs the same thing with a different number of arguments then defaults will be used.
When a method overload performs a function differently based on its parameters then overloading will continue to be used.
I used optional back in my VB6 days and have since missed it, it will reduce a lot of XML comment duplication in C#.
I've been using Delphi with optional parameters forever. I've switched to using overloads instead.
Because when you go to create more overloads, you'll invariably conflict with an optional parameter form, and then you'll have to convert them to non-optional anyway.
And I like the notion that there's generally one super method, and the rest are simpler wrappers around that one.
I will definitely be using the optional parameters feature of 4.0. It gets rid of the ridiculous ...
public void M1( string foo, string bar )
{
// do that thang
}
public void M1( string foo )
{
M1( foo, "bar default" ); // I have always hated this line of code specifically
}
... and puts the values right where the caller can see them ...
public void M1( string foo, string bar = "bar default" )
{
// do that thang
}
Much more simple and much less error prone. I've actually seen this as a bug in the overload case ...
public void M1( string foo )
{
M2( foo, "bar default" ); // oops! I meant M1!
}
I have not played with the 4.0 complier yet, but I would not be shocked to learn that the complier simply emits the overloads for you.
Optional parameters are essentially a piece of metadata which directs a compiler that's processing a method call to insert appropriate defaults at the call site. By contrast, overloads provide a means by which a compiler can select one of a number of methods, some of which might supply default values themselves. Note that if one tries to call a method that specifies optional parameters from code written in a language which doesn't support them, the compiler will require that the "optional" parameters be specified, but since calling a method without specifying an optional parameter is equivalent to calling it with a parameter equal to the default value, there's no obstacle to such languages calling such methods.
A significant consequence of binding of optional parameters at the call site is that they will be assigned values based upon the version of the target code which is available to the compiler. If an assembly Foo has a method Boo(int) with a default value of 5, and assembly Bar contains a call to Foo.Boo(), the compiler will process that as a Foo.Boo(5). If the default value is changed to 6 and assembly Foo is recompiled, Bar will continue to call Foo.Boo(5) unless or until it is recompiled with that new version of Foo. One should thus avoid using optional parameters for things that might change.
It can be argued whether optional arguments or overloads should be used or not, but most importantly, each have their own area where they are irreplaceable.
Optional arguments, when used in combination with named arguments, are extremely useful when combined with some long-argument-lists-with-all-optionals of COM calls.
Overloads are extremely useful when method is able to operate on many different argument types (just one of examples), and does castings internally, for instance; you just feed it with any data type that makes sense (that is accepted by some existing overload). Can't beat that with optional arguments.
In many cases optional parameters are used to switch execution. For example:
decimal GetPrice(string productName, decimal discountPercentage = 0)
{
decimal basePrice = CalculateBasePrice(productName);
if (discountPercentage > 0)
return basePrice * (1 - discountPercentage / 100);
else
return basePrice;
}
Discount parameter here is used to feed the if-then-else statement. There is the polymorphism that wasn't recognized, and then it was implemented as an if-then-else statement. In such cases, it is much better to split the two control flows into two independent methods:
decimal GetPrice(string productName)
{
decimal basePrice = CalculateBasePrice(productName);
return basePrice;
}
decimal GetPrice(string productName, decimal discountPercentage)
{
if (discountPercentage <= 0)
throw new ArgumentException();
decimal basePrice = GetPrice(productName);
decimal discountedPrice = basePrice * (1 - discountPercentage / 100);
return discountedPrice;
}
In this way, we have even protected the class from receiving a call with zero discount. That call would mean that the caller thinks that there is the discount, but in fact there is no discount at all. Such misunderstanding can easily cause a bug.
In cases like this, I prefer not to have optional parameters, but to force the caller explicitly select the execution scenario that suits its current situation.
The situation is very similar to having parameters that can be null. That is equally bad idea when implementation boils to statements like if (x == null).
You can find detailed analysis on these links: Avoiding Optional Parameters and Avoiding Null Parameters
One caveat of optional parameters is versioning, where a refactor has unintended consequences. An example:
Initial code
public string HandleError(string message, bool silent=true, bool isCritical=true)
{
...
}
Assume this is one of many callers of the above method:
HandleError("Disk is full", false);
Here the event is not silent and is treated as critical.
Now let's say after a refactor we find that all errors prompt the user anyway, so we no longer need the silent flag. So we remove it.
After refactor
The former call still compiles, and let's say it slips through the refactor unchanged:
public string HandleError(string message, /*bool silent=true,*/ bool isCritical=true)
{
...
}
...
// Some other distant code file:
HandleError("Disk is full", false);
Now false will have an unintended effect, the event will no longer be treated as critical.
This could result in a subtle defect, since there will be no compile or runtime error (unlike some other caveats of optionals, such as this or this).
Note that there are many forms of this same problem. One other form is outlined here.
Note also that strictly using named parameters when calling the method will avoid the issue, such as like this: HandleError("Disk is full", silent:false). However, it may not be practical to assume that all other developers (or users of a public API) will do so.
For these reasons I would avoid using optional parameters in a public API (or even a public method if it might be used widely) unless there are other compelling considerations.
One of my favourites aspects of optional parameters is that you see what happens to your parameters if you do not provide them, even without going to the method definition. Visual Studio will simply show you the default value for the parameter when you type the method name. With an overload method you are stuck with either reading the documentation (if even available) or with directly navigating to the method's definition (if available) and to the method that the overload wraps.
In particular: the documentation effort may increase rapidly with the amount of overloads, and you will probably end up copying already existing comments from the existing overloads. This is quite annoying, as it does not produce any value and breaks the DRY-principle). On the other hand, with an optional parameter there's exactly one place where all the parameters are documented and you see their meaning as well as their default values while typing.
Last but not least, if you are the consumer of an API you may not even have the option of inspecting the implementation details (if you don't have the source code) and therefore have no chance to see to which super method the overloaded ones are wrapping. Thus you're stuck with reading the doc and hoping that all default values are listed there, but this is not always the case.
Of course, this is not an answer that handles all aspects, but I think it adds one which has not be covered so far.
I'm looking forward to optional parameters because it keeps what the defaults are closer to the method. So instead of dozens of lines for the overloads that just call the "expanded" method, you just define the method once and you can see what the optional parameters default to in the method signature. I'd rather look at:
public Rectangle (Point start = Point.Zero, int width, int height)
{
Start = start;
Width = width;
Height = height;
}
Instead of this:
public Rectangle (Point start, int width, int height)
{
Start = start;
Width = width;
Height = height;
}
public Rectangle (int width, int height) :
this (Point.Zero, width, height)
{
}
Obviously this example is really simple but the case in the OP with 5 overloads, things can get crowded real quick.
While they are (supposedly?) two conceptually equivalent ways available for you to model your API from scratch, they unfortunately have some subtle difference when you need to consider runtime backward compatibility for your old clients in the wild. My colleague (thanks Brent!) pointed me to this wonderful post: Versioning issues with optional arguments. Some quote from it:
The reason that optional parameters were introduced to C# 4 in the
first place was to support COM interop. That’s it. And now, we’re
learning about the full implications of this fact. If you have a
method with optional parameters, you can never add an overload with
additional optional parameters out of fear of causing a compile-time
breaking change. And you can never remove an existing overload, as
this has always been a runtime breaking change. You pretty much need
to treat it like an interface. Your only recourse in this case is to
write a new method with a new name. So be aware of this if you plan to
use optional arguments in your APIs.
To add a no-brainer when to use an overload instead of optionals:
Whenever you have a number of parameters that only make sense together, do not introduce optionals on them.
Or more generally, whenever your method signatures enable usage patterns which don't make sense, restrict the number of permutations of possible calls. E.g., by using overloads instead of optionals (this rule also holds true when you have several parameters of the same datatype, by the way; here, devices like factory methods or custom data types can help).
Example:
enum Match {
Regex,
Wildcard,
ContainsString,
}
// Don't: This way, Enumerate() can be called in a way
// which does not make sense:
IEnumerable<string> Enumerate(string searchPattern = null,
Match match = Match.Regex,
SearchOption searchOption = SearchOption.TopDirectoryOnly);
// Better: Provide only overloads which cannot be mis-used:
IEnumerable<string> Enumerate(SearchOption searchOption = SearchOption.TopDirectoryOnly);
IEnumerable<string> Enumerate(string searchPattern, Match match,
SearchOption searchOption = SearchOption.TopDirectoryOnly);
Both Optional parameter , Method overload have there own advantage or disadvantage.it depends on your preference to choose between them.
Optional Parameter:
available only in .Net 4.0.
optional parameter reduce your code size.
You can't define out and ref parameter
overloaded methods:
You can Define Out and ref parameters.
Code size will increase but overloaded method's are easy to understand.

Categories

Resources