Is there any case in C# code where positional arguments are not enough?
I really don't see any benefit of named arguments, on contrary I can see how overusing of named arguments could make code hard to read? So my question is, why would someone use them and how can it help in writing better code as I'm sure they were not implemented without reason?
This looks cleaner to me:
private void Foo(1, true);
then:
private void Foo(bar: 1, baz: true);
Named arguments are meant to increase readability. For example I've just used one as such
public void MarkAsDone(bool skipped) {}
Now by invoking the method without the name we have an ambiguity
MarkAsDone(true); //does true mean that it is successfully done?
Which can be resolved by clarifying with a name
MarkAsDone(skipped: true);
I think using the named parameter makes the client code way less ambiguous.
Apart from that they can be used to uniquely identify an optional parameter when there's more than one with the same type
MarkAsDone(int first, int second=0, int third=0) {}
///
MarkAsDone(1, third: 3);
I use named parameters to make call sites clearer and when I have parameters with default values. The default values case has been discussed in a number of different answers already, so let's talk about call site clarity.
An analysis with metasyntactic variables isn't going to highlight their usefulness. Consider, instead this more "real-world", if you will, example.
Let's look at a call site:
something.OpenFile(documentPath, true);
What is this going to do? It's going to open documentPath. And do something else? What else? I can't remember, even though I wrote OpenFile only a week ago.
Here are three different examples for OpenFile that are relatively realistic.
void OpenFile(string path, bool shouldOverwrite)
void OpenFile(string path, bool preserveExisting)
void OpenFile(string path, bool enableWriting)
With named parameters, we can make the call sites clear:
something.OpenFile(documentPath, shouldOverwrite: false);
It's pretty clear that the file will not be overwritten.
something.OpenFile(documentPath, preserveExisting: false);
It's pretty clear that the file will be overwritten if needed.
And finally, we have:
something.OpenFile(documentPath, enableWriting: false)
It's pretty clear that the file will be opened for reading only.
Could this particular example be solved with something else like an enum? Yes. Can you always change the code? No. Does everyone else have the same abiding hatred for bool parameters that I do? No. :-)
Can you over do it with named parameters? Yes. Do good local variable names help? Tremendously.
We found a very interesting use for named arguments when we needed to use a method like this:
private void ShowPopup(FrameworkElement content,
string title = "My Application",
bool isDialog = true,
double? width = null,
double? height = null,
double? offsetX = null,
double? offsetY = null,
bool isTransparent = false,
... etc)
where almost all parameters are optional. There are situations where you will want to leave all these parameters to their default, except one or a couple of them, such as:
PopupHelper.ShowPopup(_view, isTransparent: true);
or things like that.
They are useful - indeed implicitly required - when calling methods with optional parameters - because when you call a method of with optional parameters you must specify the ones you want to pass, otherwise you have to provide the whole list up to the last one you want to use.
Given a method like this:
public void Do(Thing thing, bool doItTwice = false, bool logResults = false,
string something = null, bool makeTeaAfterwards = false)
You then must use named parameters to avoid having to specify the whole list:
Do(thing, makeTeaAfterwards: true);
Rather than:
Do(thing, false, false, null, true);
The latter also has the disadvantage that you must replicate the defaults, which introduces the possibility of error.
I'm not sure, but I think you have misunderstood named parameters.
Please see:
http://www.dotnetperls.com/named-parameters
Basically, they are useful when you've a lot of parameters to send to a method. With named parameters you can be sure of which parameters you are sending to the method
Method1(test1: 1, ..., test20: 10);
You should use it careful, as it has a substantial performance drawback.
If you had a method signature like:
private void Foo(int bar, bool baz);
then named arguments don't help much, no.
But imagine a method signature like:
private void Foo(bool bar, int baz=0, int qux=0);
And say you wanted to pass the default value of baz but a parameter for qux, then named arguments helps there:
Foo(true, qux:1);
These days C# supports optional parameters, for example:
public void Dance(string song = "makarena",
string location = "your house",
string performer = "Michael",
DateTime? date = null,
int milliseconds = 0,
Action callback = null)
{
///party code
}
Now you can call it by skipping over some of the arguments (in any order):
Dance(location : "my house", date : DateTime.Now, performer : "Christina");
I tested the code. Sadly I didn't see Christina's sexy dance because I forgot to set the milliseconds parameter :P (Not my fault, but of those who did the API, why would they make milliseconds optional? :P).
My opinion is that the true value of this is in COM Interop and similar situations. For example Office COM objects has some methods with lots of arguments that are a pain without these (For example Word.Documents.Open).
Good practice is to keep the arguments in the correct order still.
Good practice is to not blindly remove the names when you get your readability from elsewhere.
Example function:
public void TrackDataChange(IEntity oldData, IEntity newData)
Old call:
dataTrackerService.TrackDataChange(newData: valuesFromClient.ToEntity(), oldData: valuesFromDb.ToEntity())
New call:
var oldData = new ValueEntityConverter(valuesFromDb).Entity;
var newData = new ValueEntityConverter(valuesFromClient).Entity;
dataTrackerService.TrackDataChange(newData, oldData);
Of course this compiles but the resulting data is now messed up, because
originally the order was wrong but still worked correctly because of the names
someone removed the names but didn't check the order
Not sure you can solely blame either developer...
Answered to a similar question that got deleted so I´ll post it here.. I think the Com Call argument has not been included yet:
There is one or two good reasons to use named parameters.
1) When using Com calls / Optional parameters
Imagine this:
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true;
var myFormat =
Microsoft.Office.Interop.Excel.XlRangeAutoFormat.xlRangeAutoFormatAccounting1;
excelApp.get_Range("A1", "B4").AutoFormat(myFormat, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
In C# 3.0 and earlier versions, you need to supply an argument for
every parameter.
However, you can greatly simplify the call to AutoFormat by using named and optional arguments, introduced in C# 4.0.
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );
2) Named parameters can create better / clearer code
File.Copy("source.txt", "destination.txt", true);
Unless you’re a developer that is already familiar with this method, you can only guess as to what the last Boolean parameter is for. With C# 4.0 named parameters this code can be written like this to express intent more clearly:
File.Copy("source.txt", "destination.txt", overwrite: true);
3) It shortens code
instead of using
Person person = new Person();
person.FirstName = "John";
person.LastName = "Smith";
person.DateOfBirth = new DateTime(1970, 1, 1);
you can use (depends on readability preferences)
Person person = new Person() { FirstName = "John", LastName="Smith", DateOfBirth = new DateTime(1970, 1, 1)};
Useful to ensure non-breaking code when calling against generated methods
In an application where a method has parameter values that are tied to fields in a database (e.g. a constructor for a test objects that has properties in the database), it's possible that, based on a change to the database, the order of the parameters might change. If the data types of the method parameters remain the same, and hand-rolled code (e.g. a unit test) calls the generated method, it can be very difficult to see that the hand-rolled code no longer matches the generated code. Named parameters can help prevent this.
For example:
A database has a table MyCreation with columns IsBig and IsColoured. Using an ORM, a test method to create sample data exists to populate such data:
/* Generated Code from an ORM */
public IMyCreation CreateTestObject(bool isBig, bool isColoured)
{
IMyCreation _myCreation = new MyCreation();
_myCreation.IsBig = isBig;
_myCreation.IsColoured = isColoured;
return _myCreation;
}
A method in a hand-rolled test class makes use of this:
var myCreation = mcTest.CreateTestObject(false, true);
Now, if the DB were to change, e.g. a parameter were renamed (IsBig becomes IsGrande), then the order of the parameters might change, and the generated function now becomes:
/* Generated Code from an ORM */
public IMyCreation CreateTestObject(bool isColoured, bool isGrande)
{
IMyCreation _myCreation = new MyCreation();
_myCreation.IsColoured = isColoured;
_myCreation.IsGrande = isGrande;
return _myCreation;
}
However, everything will still compile. The calling code is still valid, but no longer correct, as the value for each parameter is different.
var myCreation = mcTest.CreateTestObject(false, true);
If named parameters are used, protection against generated parameter changes is achieved:
var myCreation = mcTest.CreateTestObject(isBig: false, isColoured: true);
... this code would then break (in the case of a param rename) - which is desirable!
Or, in the case of a simple parameter swap without a rename, would continue to work without needing a fix:
var myCreation = mcTest.CreateTestObject(isBig: false, isColoured: true);
would be correct, regardless of whether the function signature is
public IMyCreation CreateTestObject(bool isBig, bool isColoured)
or
public IMyCreation CreateTestObject(bool isColoured, bool isBig)
For generated code, where ugly code is more tolerable, an approach like this might be useful to force named parameters to be used.
They can be a nice declaration of intent, and increase readability where the arguments are the same type or can be implicitly converted.
E.g
int Duration(d1,d2)
Is that from d1 to d2 or d2 - d1 ?
Intellisense might tell you if the arguments have good names, and or the documentation is correct and up to date. Or you could look at the code...
With multiple optional arguments they are even more useful, avoid rules like all optional arguments have to be the last ones, and all up to the one you want to not use the default have to be specified. Total nightmare if for some reason you need to re-factor the argument list.
You might want to think about the differences between succinct and terse. Succinct is always good, terse rarely is.
I feel it it sacrifices compactness for readability. Lets say you have a function that cleans an array of some unwanted elements. Unwanted may be: old, deprecated, unused:
// unnamed:
collection.remove(true, true, false)
// named:
collection.remove(old:true, deprecated:true, unused:false);
There are many other ways to achieve this of course, from bitwise flags to intellisense. But, when programming in Python I use named params quite allot. Of course, no strong typing there, and worse tooling.
Related
I am working on a c# library, so we are concerned with breaking backwards compatibility, but I was wondering is it possible to change just the name of a parameter and maintain backwards compatibility because of the ability to use named parameters? An example of what I am trying to do is below
[Obsolete("use ChangeSpecificFoo(SpecificFoo specificFoo)")]
public void ChangeSpecificFoo(SpecificFoo foo)
{
_specificFoo = foo;
}
//Compile error ... already defines a member called 'ChangeSpecificFoo' with the same parameter types
public void ChangeSpecificFoo(SpecificFoo specificFoo)
{
_specificFoo = specificFoo;
}
Just changing the parameter name runs the potential risk of breaking backwards compatibility because someone could be calling the method using named parameters like ChangeSpecificFoo(foo: someSpecificFoo) , but we can't deprecate the method by adding a new method with the correct parameter name because parameter names are not included in the method signature, so the compiler sees it as a duplicate.
Is there any way around this? The only alternatives I see are changing the method name so it is not a duplicate and then deprecating the old method, or waiting until we add or remove parameters from the parameter list and changing the parameter names then(this may never happen because the method is pretty stable), or just make the change and fix any breaks that we may have from code using this library as we find them.
My first inclination for this is simple: DON'T. The name of your parameter is irrelevant outside of the method body. You're right to consider people calling it out by name, and therefore potentially breaking it. However, just changing the name of the parameter gives no real benefit.
The only possible reason for changing the name is to redefine what the method does because the old name leads to confusion. In that case, the name of the method should also be changed in order to not introduce another form of confusion. (The fact that the method signatures are identical is the first and more important reason to not change parameter names. However, this is to potentially explain why you might want to.)
If however, you are still adamant about keeping the same method signature, but altering the name, you could do this. (Again, I'm strongly recommending you either don't change it at all, or rename the method as well to continue to eliminate confusion.)
One way around this would be to have the method with both parameters, but make the second optional. Have that last parameter use the old name, and then assign it over within the method.
I would also HIGHLY recommend logging any uses of the named parameter, to see if your concern is valid about people calling it as a named parameter.
public void ChangeSpecificFoo(SpecificFoo specificFoo = null, SpecificFoo foo = null)
{
if (foo != null && specificFoo == null)
{
// Add any other details you can, especially
// to figure out who is calling this.
Log("Someone used a name parameter!!");
}
_specificFoo = specificFoo ?? foo;
}
As Dmitry Bychenko pointed out in the comments, this will not stop anyone from calling this method like so: ChangeSpecificFoo(null, new SpecificFoo()), which will trigger a logging.
His observation introduces another reason why this is a bad idea: You're now introducing ANOTHER way for people to "incorrectly" call your method. Therefore, I'll repeat my advice from the top of my answer: DON'T do this, unless you really really really need to change that parameter name.
So yes, as the title says, is there was a way to deal with repetitious parameters easily?
For example, say I'm making a class with many methods. Let's say most of the methods take the same method signature and it's rather long. Made up example:
void Method(int x, int y, int z = 0, string label = null, isNeverGonnaGiveYouUp = true)
I'm aware you can make an alias for a class...
using Alias = System.Console;
I haven't found anything similar for method parameters and didn't know if I was left to repeatedly copy and paste for everything, (and all changes). Or maybe it's possible with macros or something? Though I'm not much of a macro guy.
It'd be neat to have as a language feature. Something like...
using ArgList = params (int x, int y, int z = 0, string label = null, isNeverGonnaGiveYouUp = true)
void Method(ArgList)
Or for times where there's long generic parameters...
using GenArgList = params (Action<int, int, int, string, bool>)
And maybe generic methods...
using Gen = typeof (int, int, int string, bool)
void Method<Gen>(/* parameters here */)
I'm sure as with most other cases it's either not worth implementing or there's a valid reason for why it shouldn't be implemented. (Or maybe I'm just nuts and this is a terrible idea in general.) But copy/paste is getting old.
Thanks.
EDIT: Regarding the "just make it a class" argument, supercat makes a valid point. In my case I'm making a class that chains methods together LINQ style and each set of params can be different.
What you are asking for is meta-progamming features, which are just about absent from C#.
Lisp, C++ and many functional languages can do what you ask, but I don't see it happening in C# any time soon.
You can use T4 text templates to generate the code, but after that you're on your own.
I am working on my own command line arguments parser and after reading dozens of articles regarding method overloading I am still not certain if I am doing it right.
Am I getting any benefit from overloading methods this way? I know I could just write the entire thing in a single method (with default value parameters) by branching, but I'm experimenting overloads at the moment and I would like to know whether to continue on this path or not.
public static class MyParsers
{
private static List<string> args;
static MyParsers()
{
args = Environment.GetCommandLineArgs().ToList();
}
public static List<string> ParseOptions()
{
return ParseOptions(false);
}
public static List<string> ParseOptions(bool toLowercase)
{
// DEBUG: Change command line arguments here.
var arguments = args;
return !toLowercase
? arguments
: arguments.MyExtToLower();
}
public static bool OptionExists(string option)
{
return OptionExists(option, false);
}
public static bool OptionExists(string option, bool toLowercase)
{
var list = ParseOptions(toLowercase);
for (var i = 1; i < list.Count; i++)
{
if (list[i].StartsWith(option)) return true;
}
return false;
}
}
Yes that is the correct way to use overloads.
One thing to note about default parameters.
If you have two assemblies, A and B, A calls the function in B.
If you change the default in B:
using default values for parameters you need to recompile both assembly A and B for this change to take effect
using overloads you only need to recompile B.
This is because for default parameters, at compile time the compiler inserts the default values.
Yes, that's fine.
As you already know, you could also use optional parameters with default values, if your overloads only call another method with a default value (this would reduce the number of line of code).
Yep, this is how overloads work.
But a side-node:
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?
Source: Should you declare methods using overloads or optional parameters in C# 4.0?
The "problem" with optional parameters is that if the default value is changed in some future version X of your assembly A then any client assemblies C that reference A will need to be recompiled in order to "see" the change -- loading an updated version of A will cause them to call the new methods with the old default values.
If this is not a potential problem then using optional parameters is more convenient. The equivalent version that emulates optional parameters using multiple overloads does not have this issue because in that case the default value is baked into assembly A instead of into C.
I think your style of overloading is fine.
If you thought you might have loads of different parsing arguments (ToUpperCase etc)
rather than have one class with lots of overloaded methods you might consider using object inheritance and have a LowerCaseParser, CamelCaseParser etc...
I am converting a large VB.Net project to C#. I used an free automated tool to convert them. VB is happy with empty parameters passed in and uses default values for them supplied in the method definition.
After the conversion, there are many calls in the C# code looking like this:
GetElement(ndFirst, WAIT_AFTER_BATCH,false, , , "WAIT");
And compiler is not happy...
Can someone point me in the right direction if I can edit the C# files automatically(since intellisense knows how to) to fill these default values when I am making the call.
I am assuming that the C# version of your methods has the default parameters specified correctly, ex.
public void SomeMethod(int paramA = 0, int paramB = 1, int paramC = 2){
...
}
If you want to call the method and accept the default for paramB (as in your example), then you need to name the parameters
SomeMethod(paramA: 12, paramC: 20);
This would collect values for paramA and paramC whilst using the default for paramB.
Furthermore, since paramA is in the correct position, this will also be correct
SomeMethod(12, paramC: 20);
Alternatively, if the parameter you want to leave out is the last one, you can simply leave it out and call your method like so
SomeMethod(12,20);
Where paramA = 12, paramB = 20 and paramC will use the default of 2.
Unfortunately I am unaware of an automatic way to fix these. Likewise, to speed you up, you can use ReSharper and create a formatter to enforce using named arguments. Then run a simple regex over your project and clean out any instances of ',,'
Note I am in no way affiliated with JetBrains or ReSharper. I am a mere client of this company.
I have also experience that when i shifted from VB.Net to C#.Net
Here's what you will do:
First of all import InteropServices NameSpace
using System.Runtime.InteropServices;
Then create a function or procedure like this one below: (in my case it's a function)
static string ResizeImage(string imgTemp,
[Optional, DefaultParameterValue(200)] int xLength)
{
// Do something HERE
}
I fixed the compiler errors in generated cs files for the common libraries
Wrote a utility that goes over the method definitions in the file and prepared a catalog of the methods and ParamterInfos in a dictionary.
var methodInfos = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
//this is not exact for methods with different signatures.
foreach (var methodInfo in methodInfos)
{
if(!methodCatalog.ContainsKey(methodInfo.Name))
methodCatalog.Add(methodInfo.Name, methodInfo.GetParameters());
else
{
methodCatalog.Add(methodInfo.Name + "__" + Guid.NewGuid() , methodInfo.GetParameters());
}
}
Wrote another method where I tokenize a line for the method call get the method parameters (they are all "," seperated)
For the empty parameter values I set the values from my method dictionary
for(int i = 0; i < paramValues.Length; i++)
{
if( string.IsNullOrEmpty( paramValues[i].Trim()) )
{
paramValues[i] = currentParameterInfos[i].DefaultValue.ToString();
}
}
This is error prone but it is better than goin in the files and editing them by hand.
I recently read the following overflow post:
Hidden Features of C#
One of the features pointed out was the arglist. Why would one choose this or the alternatives as a means of using a variable length argument list to a method? Also, note that I would probably not use this kind of construct in my code unless a corner case warranted doing so. This is more of a question of semantics than whether it is even practical or prudent to even use variable length arguments. So does anyone know which is better and why?
[Test]
public void CanHandleVariableLengthArgs()
{
TakeVariableLengthArgs(__arglist(new StringBuilder(), 12));
object[] arr = { new StringBuilder() };
TakeVariableLengthArgs2(arr);
TakeVariableLengthArgs3(
new Dictionary<string, object>
{ { "key", new StringBuilder() } });
}
public void TakeVariableLengthArgs(__arglist)
{
var args = new ArgIterator(__arglist);
var a = (StringBuilder)TypedReference.ToObject(args.GetNextArg());
a.Append(1);
}
public void TakeVariableLengthArgs2(params object[] args)
{
var a = (StringBuilder)args[0];
a.Append(1);
}
public void TakeVariableLengthArgs3(Dictionary<string, object> args)
{
var a = (StringBuilder)args["StringBuilder"];
a.Append(1);
}
I would certainly never use __arglist, since it's undocumented and nobody knows what it means in any case.
I'd also avoid variable-length argument lists for as long as possible, and instead rework my design to understand what is truly variable, and to model that variability in a less platform-dependant manner.
It depends on the case. I've used params in cases where I have a variable number of arguments and it significantly adds to the readability of the calling code.
For example, I have a class that represents a TIFF document and allows access to a collection of pages which can be reordered and interspersed with other TIFF documents. Since one of the most common tasks our customers want is the ability to easily combine multiple TIFF documents into a single, we also provide the following two utility methods:
public static void Combine(Stream output, params Stream[] sources) { /* ... */ }
public static void Combine(Stream output, params string[] sourceFiles) { /* ... */ }
which in usage make the client code feel really nice:
using (FileStream output = new FileStream(outputPath, FileMode.Create)) {
TiffDocument.Combine(output, tpsCoverSheetPath, mainDocumentPath, tpsTrailerPath);
}
In general, you are probably better off avoiding undocumented features of the language - for several reasons.
They are more likely to change then the established, documented features
They may have side-effects and implications that are not obvious in their usage
Other developers will not be familiar with them and will have a harder time maintaining your code
Refactoring tools (like VS itself or Resharper) are unlikely to be able to recognize them
They take away clarity from the intent of your code
There are language-supported alternatives to most of them
In the specific case of the __arglist, you can achieve the same capabilities with the language supported params keyword, which allows you to create type-safe variable argument lists for methods in C#. As a practice, though, I would be careful using it as it can obfuscate your code if used inpropertly - good use cases (like those in string.Format() which accepts variable arguments) - are less frequent than you would think.
C# 4 will have a better mechanism for this; named and optional arguments:
static void Main(string[] args)
{
// The method can be called in the normal way, by using positional arguments.
Console.WriteLine(CalculateBMI(123, 64));
// Named arguments can be supplied for the parameters in either order.
Console.WriteLine(CalculateBMI(weight: 123, height: 64));
Console.WriteLine(CalculateBMI(height: 64, weight: 123));
// Positional arguments cannot follow named arguments.
// The following statement causes a compiler error.
//Console.WriteLine(CalculateBMI(weight: 123, 64));
// Named arguments can follow positional arguments.
Console.WriteLine(CalculateBMI(123, height: 64));
}
static int CalculateBMI(int weight, int height)
{
return (weight * 703) / (height * height);
}
I would prefer to not use any of the three techniques described here. I would instead design a value object that has strong types wherever possible, and possibly even nullable types. If push comes to shove you can create a generics-typed value object too.
There's just all so much code smell in this way of coding for me. A variable length collection of object ? Wouldn't pass unnoticed in my code review.
Edit:
And if it DID pass my code review the parameter would in all likelyhood be an IEnumerable instance and none of the three suggestions items. IEnumerable is the leanest thing that could encapsulate my needs.