C# default parameters workaround - c#

Is there a workaround for default parameters? In C++ I would use
int foo(int k, bool check = false)
A tedious workaround would be to overload a function. An easier one? (There is no way just adding the variable and checking the calls of the function!!)
Thanks,
Sun

The C# (before 4.0) didn't support the default parameters. Even in c# 4.0 the default parameters are a bit different than in C++ - they're stored in metadata and, when you reference the assembly with default parameters, they're compiled into your code. So, if the default value was changed in the future, your code will still pass the OLD default value, which may cause the bad effect. So, use the overloaded functions with a single parameter and double parameters and call the one with more parameters passing the default value. Such approach will have a least side effect.

In C#4, you can do the same. So this is allowed:
int foo(int k, bool check = false){
...
}
There are also possible to use named arguments in C#4 so you can call this method in many different ways:
foo(10, true);
foo(10);
foo(k: 10, check: true);
foo(check: true, k: 10);
named arguments are useful if you have several optional parameters, and only want to specify one of them that is not the first optional one, or to improve readability on the calling side.

In C# 4.0 default and named parameters is supported now.
http://msdn.microsoft.com/en-us/library/dd264739.aspx

You can use optional parameters in your assemblies if they are build with MSBuild 4.0 (VS2010) even if you are targeting the .Net 2.0 framework.
The syntax is just like you said:
int foo(int k, bool check = false)
{
}

To elaborate on Denis Mazourick's answer about using default optional parameters in C# 4.0 and how the default values get compiled into the consuming class, try this.
Create a class library with the following code and build it:
public class ClassWithDefaultParameters {
public string Msg { get; set; }
public ClassWithDefaultParameters(string msg = "Hello World") {
Msg = msg;
}
}
public class ClassWithConstructorOverloads {
public string Msg { get; set; }
public ClassWithConstructorOverloads(string msg) {
Msg = msg;
}
public ClassWithConstructorOverloads() : this("Hello World") {}
}
Now create a console application and reference the dll you just built (not the project, but the actual dll). Place this in your code and build the console application.
static void Main() {
var cwdp = new ClassWithDefaultParameters();
var cwco = new ClassWithConstructorOverloads();
Console.WriteLine(cwdp.Msg);
Console.WriteLine(cwco.Msg);
}
When you run the application, the output will be as you expected:
Hello World
Hello World
Now open up the class library, and change both "Hello World" in "Hello Europe". Recompile the library and copy the dll to the output folder of the console application. Do not rebuild the console application.
When you run the console application again, the output will be:
Hello World
Hello Europe
Probably not what you expected! It's not until you rebuild the console application that both lines will print Hello Europe.
I didn't know this and I think I won't use the default parameters because of this. What's worse is that Microsoft doesn't mention this on the MSDN page.

well, there is no easier way, you could use param feature, but it is risky as well.
have a look at example for string.Format() where you can use it like:
stringA.Format("{0} is {1}", str1, str2)
that way you can pass any number of params, but it is quite tricky how u consume it and could be quite error prone

Related

Specifying locale for string interpolation in C#6 (Roslyn CTP6)

String interpolation in C#6 lets me write:
decimal m = 42.0m;
string x = $"The value is {m}";
However, a very common use case for string formatting is to specify the locale used for formatting the values. Let's say I need to use InvariantCulture for the formatting operation above, what is the syntax for that ?
This discussion suggests that I should be able to do this:
string x = INV($"The value is {m}");
Where INV is defined as
public static string INV(IFormattable formattable)
{
return formattable.ToString(null, System.Globalization.CultureInfo.InvariantCulture);
}
However, this does not work. It compiles, but it leaves my program hanging at in cmd.exe at startup - as if klr.exe, that I assume is being invoked, hangs (Compiler bug?)
This is an ASP.NET 5 Console Project in VS15 CTP 6.
What you have should work. It's the correct syntax. There's also a convenient method on the "System.FormattableString" abstract class which has the same effect as the suggested "INV" helper method.
using static System.FormattableString;
...
string x = Invariant($"The value is {m}");
I finally figured this out. As it turns out, the compiler feature relies on two types, System.FormattableString, and System.Runtime.CompilerServices.FormattableStringFactory. These were not available for my project - I guess they might not yet have made it into all platforms for CTP6.
This apparently made the compiler hang as described. Once I pulled the code for those two types from the CoreCLR code and added it to my project, my code works as expected.
This was figured out through code comments for the InterpolationTests. Hooray for the source being available :-)

Is this the right way to overload a method?

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...

VB.NET to C# conversion, default parameter values

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.

Is there .net magic to get parameter values by name in console application?

I've been developing .net console applications using C# and have always just dictated what order parameters must be inserted in so that args[0] is always start date and args[1] is always end date, for example.
however I would like to move over to using named parameters so that any combination of parameters can be sent in any order, such as the typical "-sd" would prefix a start date.
I know I could parse through the args[] looking for "-" and then read the name and look the next position for the accompanying value, but before doing that wanted to see if there was any kind of baked in handling for this rather standard practice.
is there something like this out there already that could do as such:
DateTime startDate = (DateTime)((ConsoleParameters)args[])["sd"]
I'm using C# and .Net 4
There is nothing built into the core framework.
A lot of people think NDesk.Options is useful for this sort of thing. Check out this example (taken directly from the provided link):
string data = null;
bool help = false;
int verbose = 0;
var p = new OptionSet () {
{ "file=", v => data = v },
{ "v|verbose", v => { ++verbose } },
{ "h|?|help", v => help = v != null },
};
List<string> extra = p.Parse (args);
Yes, the "magic" is that this is a common problem and it has been adequately solved. So I recommend using an already written library to handle parsing command line arguments.
CommandLineParser has been great for me. It is reasonably documented and flexible enough for every type of command line argument I've wanted to handle. Plus, it assists with usage documentation.
I will say that I'm not the biggest fan of making a specific class that has to be adorned with attributes to use this library, but it's a minor point considering that it solves my problem. And in reality forcing that attributed class pushes me to keep that class separate from where my app actually retrieves it's settings from and that always seems to be a better design.
You can use NDesk.Options.
There is no such a thing as named parameters. "-sd" is just a choice for a specific application. It can be "/sd" as well. Or "sd=". Or whatever you want.
Since there are no named parameters, there is nothing inside .NET Framework which let you use the "-sd" syntax.
But you can quite easily build your own method to get a set of "named parameters" for your app.
Edit: or, even better, you can use an existing library, like suggested in other answers.
Edit: reading the answer by #Sander Rijken, I see that I was wrong: there were still an implementation of "-sd" syntax in .NET 4.0 before the release. But since it was dropped before the final release, the only ways are still to create your own method or to use an existing library.

CA1026 (all parameters should have default values) and extension methods

Premise
When using code analysis (or fxCop) with C# optional parameters you can get a warning of CA1026. The short reason1 for this is not suppling all parameters with a default value.
The declaration below rightly generates this warning
public Color GetColor(bool red, bool blue = true, bool green = true)
However there is a situation where you could not supply all parameters with a default, and that is extension methods. So the declaration below generates the warning because of the first parameter:
public static bool ValidateRules(this string s, Rules rules = Rules.Default)
The compiler will not let you specify a default value on the this parameter so the only two solutions is to:
Ignore the warning, which I do not like doing because it leads to bad practices.
Not use extension methods, which I do not like doing because I find extension methods make the code more readible.
Questions
Are the above two options the only
way to solve this?
Is fxCop/Code
Analysis incorrect in it's check?
The long reason
It's not warning you for not having defaults for all parameters - it's warning you for using optional parameters at all.
Personally I would disable this particular warning. When used with care, I think optional parameters are fine. You should think carefully about them particularly in terms of versioning of the default parameter value and in terms of languages which don't support them (including C# before v4) but in many environments the downsides really aren't an issue - and you can end up with much simpler code than by specifying overloads all over the place.
An argument that I am missing in Jon Skeet's answer is also about maintainability: Default values are always filled in with it's value in the IL (intermediate language). This is an issue if you're using external libraries.
Here are steps to reproduce a simple example:
Create a console app
Add a ClassLibrary project to it
Add the following code:
Program.cs
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var obj = new Class1();
Console.WriteLine(obj.Foo());
Console.ReadKey();
}
}
}
and in your Class1.cs
namespace ClassLibrary1
{
public class Class1
{
public string Foo(string str = "http")
{
return str;
}
}
}
If you run it you will see 'http', as expected.
Now change "http" to "https"
Compile only the library (maybe even unload the console project)
Copy the dll from the library's bin folder to the console app's bin folder by hand
Run the console app from the command line, not from within VS!
You will still see http! With ILSpy you can see that http is hardcoded in the console app.
In this case this could lead to a security issue if the developer thinks he is safe by replacing the "http" to "https" in the default value.
So if external libraries are updated always compile your code again. Or just don't use default values.
Just create a separate method:
public string Foo()
{
return Foo("https");
}
public string Foo(string str)
{
return str;
}
You can suppress the warning on a case-by-case basis.

Categories