I have a question wheater or not it is possible (and if it is, how) to access class
members from inside a Func<T, TResult>
delegate.
For example, I have the following class
:
class NinjaTurtle
{
public string Sound { get; set; }
public Func<string, string> DoNinjaMove { get; set; }
}
Now I'd like to do this
NinjaTurtle leonardo = new NinjaTurtle();
leonardo.Sound = "swiishhh!";
leonardo.DoNinjaMove = (move) => {
if(move == "katana slash") return leonardo.Sound;
return "zirp zirp zirp";
}
The problem is, how do I correctly access the property Sound
, when I define the callback function? Is it OK to just use the reference to the instance from outside the function? Would this still work when I pass the object to another method, or even when this would be part of a dll, and I would return the object leonardo from a function in the dll? Would it "survive" serialization / deserialization?
(Thanks Vladimir and Lee, the question is now more specific to what I would like to know).
You can use closures. A closure will be an anonymous delegate or lambda expression which may reference variables, methods, properties, events or anything from an outer scope (oops, it's your case!).
leonardo.DoNinjaMove = (move) => {
// THIS IS VALID! IT'S A CLOSURE! You can access leonardo reference within
// the closure!!
if(move == "katana slash") return leonardo.Sound;
return "zirp zirp zirp";
}
Anyway, DoNinjaMove
is Func<string, bool>
. If you want to return Sound
value, it should be refactored to Func<string, string>
.
Further details about how closures work and why you can safely use outer scope's references within them can be found on this other Q&A here in StackOverflow:
Yes, there's no problem with that. Closures are a very interesting feature that most modern languages own and it's a must-have feature for languages that have incorporated functional programming. Anyway, it's a must-have feature! :)
If you came here from Google specifically wanting to code a Lambda function as a class member declared inside the class body, read on...
I found this post through google, because I was looking for a way to declare the Lambda Func as a member method of the class itself. You can declare a Func inside of a class but you can't directly assign to it in the same line. Example:
public class myClass {
public Func<string,string> DoNinjaMove; //Can't declare method body here.
}
The solution is to assign the Lambda function body inside the Constructor of the class like this:
public class myClass {
public Func<string,string> DoNinjaMove; //Can't declare method body here.
public myClass()
{
DoNinjaMove = (someString) =>
{
//Do something here
return anotherString;
}
}
}
Now DoNinjaMove is a member of myClass and it's body is also declared inside myClass. DoNinjaMove has access to all members of myClass, and you get the ability to pass DoNinjaMove to other classes/objects for them to call it.
I probably wouldn't recommend this design pattern unless you absolutely know what you're doing. In my case, another library I was using demanded I pass it a Lambda function with a specific input and return type, but I needed the function to be a member of my own class where it had access to class data for the sake of elegance and encapsulation. This is the solution I came up with.
This will capture the variable leonardo
in a closure and will work but I don't think this is a good design but it is hard to suggest something different without context.
var leonardo = new NinjaTurtle();
leonardo.Sound = "swiishhh!";
leonardo.DoNinjaMove = (move) =>
{
if (move == "katana slash")
{
return leonardo.Sound;
}
else
{
return "zirp zirp zirp";
}
}
You may want to consider using Func<NinjaTurtle, String, String>
and pass the turtle in explicitly.
leonardo.DoNinjaMove = (turtle, move) =>
{
if (move == "katana slash")
{
return turtle.Sound;
}
else
{
return "zirp zirp zirp";
}
}
But this does still not look like a convincing design to me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With