I'm creating code by using CodeDom. However, CodeDom does not support lambda statements. So I'm now trying to mimic a lambda statement by creating a local method and pass on the method as a parameter to another method. Like so:
public string MainMethod(string myParameter)
{
string g() { return instance.MainMethod(myParameter); }
return someOtherMethod(g);
}
The method 'MainMethod' is already generated by using CodeDom
and I'm trying to get the local method in there. However, I cannot find a way to do that up to this point. I could use some help with that.
I already tried adding a CodeMemberMethod to a CodeMemberMethod but there seems to be no way to do that. I cannot seem to find any alternatives.
Currently my CodeDom code is using MethodInfo as a base:
var method = new CodeMemberMethod();
method.Name = methodInfo.Name;
method.ReturnType = new CodeTypeReference(methodInfo.ReturnType);
//left out parameter stuff
var gMethod = new CodeMemberMethod() { Name = "g", ReturnType = new CodeTypeReference(methodInfo.ReturnType) };
gMethod.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeVariableReferenceExpression("instance"), methodInfo.Name), parameterReferences.ToArray())));
method.Statements.Add(gMethod);
Now, the pain is in the last statement. I'm actually trying to add a CodeMemberMethod to a CodeMemberMethod, which is not allowed via the Statements property. Is there any way to do that in another way?
Local functions were not a supported language construct until C# version 7. CodeDOM was designed much earlier and does not cover all C# feature, even of the then-current version of C#. In other words, there is, unfortunately, no way to declare a “local method” and add it to the Statements collection of another method.
Instead, consider declaring a separate private method. Your class's public interface will remain unaffected and, most likely, you will achieve what you want. However, no implicit access to the 'outer method's' parameters will be possible.
Also, consider looking at this answer for further ideas.
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.
Let's say I have a class as follows:
public class AcceptMethods
{
public int Accept(string s, int k = 1)
{
return 1;
}
public int Accept(object s)
{
return 2;
}
public int Accept(IEnumerable<object> s)
{
return 7;
}
public int Accept(IList<object> s)
{
return 4;
}
}
Now, if I try to consume this in code, I use something like this:
object[] list = new object[] { "a", new object[0], "c", "d" };
Assert.AreEqual(7, list.Select((a)=>((int)new AcceptMethods().Accept((dynamic)a))).Sum());
The reason that it's 7, is because overload resolution prefers [IList<object>] over [IEnumerable<object>] and [object], and because [string, int=default] has preference over [object].
In my scenario, I'd like to get the best matching overload using reflection. In other words: 'best' is defined as 'c# overload resolution'. E.g.:
int sum = 0;
foreach (var item in list)
{
var method = GetBestMatching(typeof(AcceptMethods).GetMethods(), item.GetType());
sum += (int)method.Invoke(myObject, new object[]{item});
}
Assert.AreEqual(7, sum);
While the scenario I sketch has only 1 parameter, the solution I seek can have multiple parameters.
Update 1:
Because I received a comment that this is too difficult for SO due to the difficulties of overload resolution implementation (which I am well aware of), I feel inclined to send an update. To give my argument some power, this was my first attempt, which uses the default .NET binder that handles the overload resolution:
private MethodBase GetBestMatching(IEnumerable<MethodInfo> methods, Type[] parameters)
{
return Type.DefaultBinder.SelectMethod(BindingFlags.Instance | BindingFlags.Public | BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod,
methods.ToArray(), parameters, null);
}
This version already seems to do simple overload resolution correctly, but fails to work with optional parameters. Because .NET afaik works with type binding like I show here, I suppose that the solution could be implemented fairly easy.
This is a massive subject, requires quite a lot of work and certainly cannot be wrapped up in an SO answer in my opinion. I suggest you read through the C# spec and read the formal rules defining overload resolution (also, please pay attention to generic methods) and try to implement them up to the point that satisfies your needs.
Update
Optional (i.e. parameters with default values) are not a trivial case - and the Reflection binder makes no attempt at all to fill them in - that's because it's a compiler's job to identify the default values, pull them out and inject them into a call to such a method.
You need a multi-pass approach that's something like this (note - does NOT include generics):
Search manually for a method whose number of parameters and types of those parameters match exactly the number and types of arguments you've got. If you find a match - use it and bunk out.
Now identify the 'candidate list' of methods for your overload selection (generally that's by name - you might also exclude generics here - unless you're going to try and bind those too).
If none of those methods have optional parameters then you might be able to go ahead and use the default binder as per your question to find the match (if not, you need a argument/parameter-ranking algorithm based on the types - if so, skip to 5).
Re-running through the candidate list built in 3), pull out all the optional parameters and incorporate their default values into your own parameter lists (you might need to build a separate set of parameters for each method at this point, including those that you have been supplied, but also the defaults).
Run your ranking algorithm for these methods built in 3) and possibly 4) to identify the best match (you seem to have a good handle on this so I'm not going to go through it all here - it's not a simple algorithm and I frankly can't quote it all verbatim here either!).
Your ranking algorithm should produce a clear winning method - i.e. with a unique high score or similar. If you get a clear winner, then that's the one you bind. Otherwise you have an ambiguity and you have to bunk out.
You might be interested in my own SO at this point - Default parameters and reflection: if ParameterInfo.IsOptional then is DefaultValue always reliable? - which should help you with identifying methods that have parameters with defaults, and how to lift them out.
For other people that want to do runtime overload resolution, this is a fairly complete description on how to implement it.
Important side note is that the 'dynamic' trick doesn't work in all scenario's as well (specifically: generics); it seems that the compiler is more flexible than runtime behavior.
Also note that this is not a complete algorithm/implementation (or at least I think that it isn't), but works in most cases including nevertheless. I found this to work in all cases that I encountered so far, including difficult cases like array covariance.
The scoring algorithm works as follows:
If parameter type == source type: score = 0
If the parameter is a generic type argument that is valid (generic constraints): score = 1
If the source type is implicitly convertible to the parameter type: score = 2 (see: http://msdn.microsoft.com/en-us/library/y5b434w4.aspx for all rules)
If you need to fill in a default parameter: score = 3
Otherwise calculate the score for compatibility score as below
The compatibility score is the most strict conversion between a type type A and type B (including and covariance, contravariance). For example, string[] has 1 conversion to IList (using object[] and then IList) and 2 conversions to IEnumerable (1. by using object[] and then IEnumerable or 2. by IEnumerable). Therefore, IList is the more strict conversion and is therefore selected.
Counting the number of conversions is easy:
int cnt = CountCompatible(parameter.ParameterType, sourceType.GetInterfaces()) +
CountCompatible(parameter.ParameterType, sourceType.GetBaseTypes()) +
CountCompatible(parameter.ParameterType, new Type[] { sourceType });
[...]
private static int CountCompatible(Type dst, IEnumerable<Type> types)
{
int cnt = 0;
foreach (var t in types)
{
if (dst.IsAssignableFrom(t))
{
++cnt;
}
}
return cnt;
}
To make sure that a better score is selected when a more strict conversion is used, I calculate score as 'score = 5 - 1.0 / (cnt + 2);'. The +2 ensures that you never divide by 0 or 1, leading to a score between 4 and 5.
To do overload resolution, select the method with the minimum score for all arguments. Make sure you enter default method arguments properly when invoking (see the excellent link by Andras above) and make sure you fill in the generic arguments before you return the method. If you encounter a draw for the best method: the best resolution is to throw an exception.
In case you wonder, yes... it's quite a bit of work to get it all working correctly... I plan to make a working version available in my framework once that's done. (You'll see the moment my profile has a working website link :-) )
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've begun to notice at times when I'm making method calls in C# that the names of the parameters for the method I'm calling will show up in the intellisense list appended with a colon, and that I can then format the method call thusly:
MethodCall(parameter1:value1, parameter2:value2);
Is this a new language feature? It reminds me of the way you can call stored procedures in SQL and specify parameter names like so:
spDoSomeStuff #param1 = 1, #param2 = 'other param'
Is this a similar feature? If so, to what end? If not, what is it and what is it to be used for.
It's a new feature. See here: http://msdn.microsoft.com/en-us/library/dd264739.aspx
Named parameters are standard in ObjectiveC for instance. It takes some time to get used to them but they are a good thing. Only from looking you can tell what a parameter is meant for.
It is worth mentioning, unlike optional parameters, you can skip certain arguments and pass only the parameters you are interested in.
public void Example(int required, string StrVal = "default", int IntVal = 0)
{
// ...
}
public void Test()
{
// This gives compiler error
// Example(1, 10);
// This works
Example(1, IntVal:10);
}
Named parameters allow you explicitly set the value of arguments in a custom order independent of the signature. Method signatures are defined by the argument types, ie, Foo( int i, bool b ), which will only accept arguments of type int and bool in that order. Named arguments allow you to pass b first and i second.
Scott Gu has introduced this new feature in his blog:
Optional Parameters and Named Arguments in C# 4
It's the Named and Optional Parameters that came in with C# 4.