I would like to know how to pass a property to a method.
Currently, this is my method:
public static string Pick(this IFilePicker openFileService, Func<string> getCurrentFolder, Action<string> setCurrentFolder)
I use it to pick files (with a dialog). It automatically sets the current folder of the OpenFileDialog calling the getCurrentFolder Func. If the user correctly selects a file, then, the setCurrentFolder action is called.
I'm using it like this:
Pick(openFileService, () => Settings.Current.Folder, str => Settings.Current.Folder = str);
But it looks cumbersome to me. Why use 2 parameters instead 1? I could just pass the property.
But how?
I would like to call it like this:
Pick<Settings>(openFileService, x => x.Current.Folder);
Is that even possible?
NOTE Settings.Current is a Singleton. It's autogenerated.
Unfortunately there's no clean way of doing this. The code you've got is the simplest approach, I believe.
You could change the method to accept an Expression<Func<string>> instead, then examine the expression tree to get the property... but it would be a lot of effort, be less efficient, and give you less compile-time checking. You'd still need to pass () => Settings.Current.Folder - it would only remove the need for the final parameter.
To be specific, in your case you'd need to build an expression tree that still accessed the getter for Settings.Current, but then the setter for Folder. You'd then need to compile both expression trees.
It's all feasible, but it's a lot of fiddly work. Your current approach is clunky but simple. Unless you need to do this a huge amount, I'd just accept the clunkiness.
Assuming Settings.Current doesn't change, the other option would be to pass in the name of the property, so you'd call it with:
Pick(openFileService, Settings.Current, nameof(Settings.Folder));
That would still require reflection and would be somewhat error-prone, IMO.
A property is nothing but a package of two methods, a get- and a set-method. So by providing a property within a delegate, you reference either the one or the other. Thats why you can´t read and write the properties value within the delegate.
In order to read a property you surely need some method that returns a string and expects nothing (namely a Func<string>). When you want to set a property, you´ll need something that excepts a string. but doesn´t return anything (an Action<string>).
Furthermore, let´s see how the delegate could be defined:
Pick(string file, Delegate readAndWriteDelegate)
{
// what can you do with the delegate? You don´t know if you can provide a string or if it returns one
// do I have to use this?
readAndWriteDelegate(file);
// or this?
var result = readAndWriteDelegate();
// or even this?
var result = readAndWriteDelegate(file);
// in fact I could even use this
MyClass m = readAndWriteDelegate(3);
}
I just used the existing Delegate to show there´s no way to even declare your delegate and provide its type-safety.
Leaving asside that the code above won´t even compile as we´d have to call Invoke on the Delegate, you see it´s completely unclear what your delegate actually expects and what it returns. Even if we could determine it´s some kind of a stringdelegate, it´s unclear if the delegate should return a string or expect one or even do both and thus how we can call it.
Suggested just returning the path, but actually Pick() method needs to return the file as well as setting the path.
I'd add an overload or new method to the OpenFileService which will read/set the Path in the Settings.Current object, so the calls don't have to care where the 'current' path comes from. I'm assuming that 90+ % of the time you'll always read Settings.Current.Path and Write back to Settings.Current.Path so it's probably best to make the OpenFileService handle this, rather than every call to it?
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.
I made a method to loop and clear all textbox controls in my form.
Controls.OfType<TextBox>()
.ToList()
.ForEach(tb => tb.Clear());
This works just fine, but I figured that since the first argument passed to any instance method is always a reference to the instance that I should be able to write it like this
Controls.OfType<TextBox>()
.ToList()
.ForEach(TextBox.Clear);
Unfortunately that doesn't actually work, and I don't quite understand why..
It would work if TextBox.Clear was a static method with a TextBox parameter; but instead, it's an instance method with no parameters, so the compiler can't automatically transform it to an Action<TextBox>.
Note that the CLR does support open-instance delegates (you can create one with the Delegate.CreateDelegate method), but the C# language doesn't support it.
Here's how to create an open-instance delegate that will invoke TextBox.Clear on its argument:
var action = (Action<TextBox>)Delegate.CreateDelegate(
typeof(Action<TextBox>),
null,
typeof(TextBox).GetMethod("Clear"));
The this parameter is implicit, not explicit. Foreach is expecting a method with an explicit parameter, not an implicit one.
As for why the C# language team didn't implement this feature, you'll have to ask them. They of course could have designed the language to support this, if they wanted to. There's no real point in us speculating as to why they didn't.
I'm trying to use delegates to cut down on my code in this project.
I have 4 DropDownLists in my asp.net page. In my codebehind file I'm binding them to different business object calls with data. Right now I have the following code:
DeptList.DataSource = bl.getAcademicDepts();
DeptList.DataBind();
TermList.DataSource = bl.getTerms();
TermList.DataBind();
InstructorList.DataSource = bl.getInstructors();
InstructorList.DataBind();
EEList.DataSource = bl.getEE();
EEList.DataBind();
This seems really repetitive so I decided to make a function as a shortcut
private void SourceAndBind(DropDownList d, <business layer method call>)
{
d.DataSource = <businesslayer method call>();
d.DataBind();
}
Then my first block of code simply becomes
SourceAndBind(DeptList, bl.getAcademicDepts());
SourceAndBind(TermList, bl.getTerms());
SourceAndBind(InstructorList, bl.getInstructors());
SourceAndBind(EEList, bl.getEE());
However, I don't know what to put for the second parameter. Each one of the business layer calls takes no parameters, but they each return objects of different types. I tried using delegates but I couldn't figure out how to create one without a defined return type or no parameters. Is it possible to achieve what I want with c#? I know that works in python which is where I'm coming from.
You don't need delegates to do this. Just declare the second parameter as object.
// Takes drop down list and data to assign to 'data source'
private void SourceAndBind(DropDownList d, object data) {
d.DataSource = data;
d.DataBind();
}
// Call methods from bussiness layer and bind results
SourceAndBind(DeptList, bl.getAcademicDepts());
SourceAndBind(TermList, bl.getTerms());
SourceAndBind(InstructorList, bl.getInstructors());
SourceAndBind(EEList, bl.getEE());
You could use delegates too. However, since you're only calling the method once, you can call the bussiness layer method to get the data and then pass the result to SourceAndBind. (Delegates would be useful for example if you wanted to choose one of several ways of loading the data, or if you wanted to delay loading until some later point).
Well, Func<object> would be a very general way of doing that. That's "a function with no parameters that returns an object". Any parameterless function returning a reference type should be convertible to that delegate type. However, your "usage" code wouldn't be quite right as it. It would be:
SourceAndBind(DeptList, bl.getAcademicDepts);
SourceAndBind(TermList, bl.getTerms);
SourceAndBind(InstructorList, bl.getInstructors);
SourceAndBind(EEList, bl.getEE);
Note the lack of brackets, which means these are method groups rather than method calls. (To follow .NET naming conventions I'd suggest renaming your methods to start with capital letters, btw.)
That's appropriate if you only want to call the method conditionally. As Tomas says though, you don't need to use delegates here. If you're happy for SourceAndBind to only get called after you've called the method, you can definitely just perform the method call in the argument and pass the result as object.
private void SourceAndBind(DropDownList d, Func<IEnumerable<object>> businessLayerMethod)
{
d.DataSource = businessLayerMethod();
d.DataBind();
}
IEnumerable<object> where object is your datatype.
I recently noticed the following code which basically defines a class method
public Func<string, string> SampleMethod = inputParam =>
{
return inputParam.ToUpper();
};
which is the same as doing it in the old fashioned way
public string SampleMethod(string inputParam )
{
return inputParam.ToUpper();
}
My question - why would I prefer the first over the second? My eyes are maybe more trained to understand the second style quicker. I find it similar to the difference between SMS lingo and plain old english.
Those two things are fundamentally different. The former is a field of a delegate type while the latter is really a method. The tiniest difference I can think of is that you can modify the first one dynamically at runtime and assign another method reference to it while the second is fixed.
You shouldn't normally prefer the first over the second if your purpose is to write a simple method for a class in C#.
An example that makes the first extremely fragile:
var c = new SomeClass();
c.SampleMethod = inputParam => inputParam.ToLower();
c.DoSomeTaskThatReliesOnSampleMethodReturningAnUpperCaseString();
c.SampleMethod = null;
c.DoSomeTaskThatCallsSampleMethod(); // NullReferenceException
This style of programming is common in language like Javascript where an object is fundamentally a dynamic creature built upon a simple dictionary.
They are actually not the same at all. The second is a regular member method, that returns ToUpper on the input string.
The first, on the other hand, is a Func member variable, that happens to point to a delegate, that implements the same functionality. However, as this is a method pointer, you can substitute the delegate with any other delegate of the same type at runtime. I.e. you can completely redefine what it means to call this method.
One benefit of the second way is it's better from a unit testing perspective - you can test your class and know that the method will correctly return the uppercase string. With the first method, you can change the method at runtime, so unit testing is much harder.
I don't understand when an output parameter should be used, I personally wrap the result in a new type if I need to return more than one type, I find that a lot easier to work with than out.
I have seen method like this,
public void Do(int arg1, int arg2, out int result)
are there any cases where that actually makes sense?
how about TryParse, why not return a ParseResult type? or in the newer framework return a null-able type?
Out is good when you have a TryNNN function and it's clear that the out-parameter will always be set even if the function does not succeed. This allows you rely on the fact that the local variable you declare will be set rather than having to place checks later in your code against null. (A comment below indicates that the parameter could be set to null, so you may want to verify the documentation for the function you're calling to be sure if this is the case or not.) It makes the code a little clearer and easier to read. Another case is when you need to return some data and a status on the condition of the method like:
public bool DoSomething(int arg1, out string result);
In this case the return can indicate if the function succeeded and the result is stored in the out parameter. Admittedly, this example is contrived because you can design a way where the function simply returns a string, but you get the idea.
A disadvantage is that you have to declare a local variable to use them:
string result;
if (DoSomething(5, out result))
UpdateWithResult(result);
Instead of:
UpdateWithResult(DoSomething(5));
However, that may not even be a disadvantage, it depends on the design you're going for. In the case of DateTime, both means (Parse and TryParse) are provided.
I think out is useful for situations where you need to return both a boolean and a value, like TryParse, but it would be nice if the compiler would allow something like this:
bool isValid = int.TryParse("100", out int result = 0);
Well as with most things it depends.
Let us look at the options
you could return whatever you want as the return value of the function
if you want to return multiple values or the function already has a return value, you can either use out params or create a new composite type that exposes all these values as properties
In the case of TryParse, using an out param is efficient - you dont have to create a new type which would be 16B of overhead (on 32b machines) or incur the perf cost of having them garbage collected post the call. TryParse could be called from within a loop for instance - so out params rule here.
For functions that would not be called within a loop (i.e. performance is not a major concern), returning a single composite object might be 'cleaner' (subjective to the beholder). Now with anonymous types and Dynamic typing , it might become even easier.
Note:
out params have some rules that need to be followed i.e. the compiler will ensure that the function does initialize the value before it exits. So TryParse has to set the out param to some value even if parse operation failed
The TryXXX pattern is a good example of when to use out params - Int32.TryParse was introduced coz people complained of the perf hit of catching exceptions to know if parse failed. Also the most likely thing you'd do in case parse succeeded, is to obtain the parsed value - using an out param means you do not have to make another method call to Parse
Years late with an answer, I know.
out (and ref as well) is also really useful if you do not wish your method do instantiate a new object to return. This is very relevant in high-performance systems where you want to achieve sub microsecond performance for your method. instantiating is relatively expensive seen from a memory access perspective.
Definitely, out parameters are intended to be used when you have a method that needs to return more than one value, in the example you posted:
public void Do(int arg1, int arg2, out int result)
It doesn't makes much sense to use an out parameter, since you are only returning one value, and that method could be used better if you remove the out parameter and put a int return value:
public int Do(int arg1, int arg2)
There are some good things about out parameters:
Output parameters are initially considered unassigned.
Every out parameter must be definitely assigned before the method returns, your code will not compile if you miss an assignment.
In conclusion, I basically try use out params in my private API to avoid creating separate types to wrap multiple return values, and on my public API, I only use them on methods that match with the TryParse pattern.
Yes, it does make sense. Take this for example.
String strNum = "-1";
Int32 outNum;
if (Int32.TryParse(strNum, out outNum)) {
// success
}
else {
// fail
}
What could you return if the operation failed in a normal function with a return value? You most certainly could not return -1 to represent a fail, because then there would be no differentiation between the fail-return value and the actual value that was being parsed to begin with. This is why we return a Boolean value to see if it succeeded, and if it did then we have our "return" value safely assigned already.
Creating a type just for returning values sounds little painful to me :-)
First i will have to create a type for returning the value then in the calling method i have assign the value from the returned type to the actual variable that needs it.
Out parameters are simipler to use.
It does annoy me that I can't pass in null to the out parameter for the TryParse functions.
Still, I prefer it in some cases to returning a new type with two pieces of data. Especially when they're unrelated for the most part or one piece is only needed for a single operation a moment after. When I do need to save the resulting value of a TryParse function I really like having an out parameter rather than some random ResultAndValue class that I have to deal with.
If you always create a type, then you can end up with a lot of clutter in your application.
As said here, one typical use case is a TrySomething Method where you want to return a bool as an indicator for success and then the actual value. I also find that a little bit cleaner in an if-statement - all three options roughly have the same LOC anyway.
int myoutvalue;
if(int.TryParse("213",out myoutvalue){
DoSomethingWith(myoutvalue);
}
vs.
ParseResult<int> myoutvalue = int.TryParse("213");
if ( myoutvalue.Success ) {
DoSomethingWith(myoutvalue.Value);
}
vs.
int? myoutvalue = int.TryParse("213");
if(myoutvalue.HasValue){
DoSomethingWith(myoutvalue.Value);
}
As for the "Why not return a Nullable Type": TryParse exists since Framework 1.x, whereas Nullable Types came with 2.0 (As they require Generics). So why unneccessarily break compatibility or start introducing inconsistencies between TryParse on some types? You can always write your own extension Method to duplicate functionality already existing (See Eric Lipperts Post on an unrelated subject that includes some reasoning behind doing/not doing stuff)
Another use case is if you have to return multiple unrelated values, even though if you do that that should trigger an alarm that your method is possibly doing too much. On the other hand, if your Method is something like an expensive database or web service call and you want to cache the result, it may make sense to do that. Sure, you could create a type, but again, that means one more type in your application.
I use out parameters sometimes for readability, when reading the method name is more important than whatever the output of the method is—particularly for methods that execute commands in addition to returning results.
StatusInfo a, b, c;
Initialize(out a);
Validate(a, out b);
Process(b, out c);
vs.
StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);
At least for me, I put a lot of emphasis on the first few characters of each line when I'm scanning. I can easily tell what's going on in the first example after acknowledging that some "StatusInfo" variables are declared. In the second example, the first thing I see is that a bunch of StatusInfo is retrieved. I have to scan a second time to see what kind of effects the methods may have.