I have a delegate that I define at runtime. I want it to check if a dictionary contains a particular key. One of the delegate parameters is a ref to the dictionary, so the dictionary is always the latest version (not a frozen copy).
However the key to lookup is an object field, but I don't want to pass it a ref to that object. I just want to grab the field value and use it as if it were a constant (frozen copy).
This is the exact code snippet. I pass in a ref to the netController, which allows me to check something is there using ContainsID(). The ID parameter comes from the msg object, but I just want to use the value without the reference to the container object.
Func<netController, bool> resolveFunc = delegate (netController nc)
{
return nc.ObjectRegister.ContainsID(msg.parentObjectID);
};
nc is in scope in this delegate, but msg is not. Is this do-able, or does everything need to be passed in as a parameter?
Note: I say dictionary, but its actually a dictionary-like object. ContainsID() is a wrapper for ContainsKey(). Don't worry about this part.
This is called an implicit capture of a variable by delegate, and it is definitely possible.
As long as msg is in scope outside the line that creates your delegate, C# would capture it, and let you use it inside your code:
Func<Controller,bool> MakeChecker(Message msg) {
return nc => nc.ObjectRegister.ContainsID(msg.parentObjectID);
}
Above method captures msg implicitly from the context that creates the delegate, rather than passing it as a delegate parameter. I used lambda syntax in place of anonymous delegate syntax:
Func<Controller,bool> MakeChecker(Message msg) {
return delegate (netController nc) {
return nc.ObjectRegister.ContainsID(msg.parentObjectID);
}
}
How do I store this into a delegate?
Like this:
Message msg = ...
Func<Controller,bool> myChecker = MakeChecker(msg);
Related
I'd like to write a method that takes a string parameter -- say, sLastName -- and returns a very simple Func<string> that has captured that variable and simply returns it. This doesn't work...
Func<string> MyMethod (string myStringVar)
{
return () => myStringVar;
}
...in that if sLastName is "Smith", and I call MyMethod(sLastName).Invoke(), I'll get back "Smith"; but if I then set sLastName to "Jones" and call MyMethod again, I'll still get back "Smith".
So, to make using MyMethod as simple as possible, I'd like to be able to pass sLastName in as a string, and then (assuming sLastName has been declared, is in scope, etc.), by somehow leveraging the Expression class, return a Func<string> with sLastName embedded as a captured variable... like so...
MyMethod("sLastName").Invoke()
...and it would return the current value of sLastName. But I can't see any way of using strings to build Expressions, and haven't yet found such in StackOverflow. Any way to do this?
Thanks in advance! (By the way, I know I can just create the lambda on the fly and pass it in as a parameter; just looking for something even simpler, where I can use only the name of the variable.)
What you really want is for myStringVar to be declared as a ref variable in MyMethod so that it's passed by reference instead of by value (which will copy the value and is why you don't see the updated value). That way the lamda has a reference to myStringVar and will thus return the latest value whenever called. However, ref variables aren't allowed to be referenced in lambda functions.
In your code, you're passing by value:
Func<string> MyMethod (string myStringVar)
{
return () => myStringVar; // When MyMethod is called, the value of myStringVar inside this function and thus the lambda is a copy of what was passed in
}
This would be similar, but without knowing what you're trying to accomplish I'm not sure if it will work for your scenario:
public static void Main()
{
var myStringVar = "Smith";
Func<string> returnMyString = () => MyMethod(ref myStringVar);
Console.WriteLine(returnMyString());
myStringVar = "Jones";
Console.WriteLine(returnMyString());
}
public static string MyMethod(ref string myStringVar)
{
return myStringVar; // myStringVar holds a reference to the one from the Main program and so returns the latest value
}
The output is:
Smith
Jones
Here's a .net fiddle with the example
I was looking around here for the answer to this question, and I found a lot of similar questions
Passing just a type as a parameter in C#
X is a variable but used like a type when trying to cast
how to adjust "is a type but is used like a variable"?
How to pass an Object type to Type parameter in C#
Generic List<T> as parameter on method, Initializing a Generic variable from a C# Type Variable
How do I use reflection to call a generic method?
Reflection To Execute Class With Generic Type
but I wasn't able to use any of them to solve my particular issue.
Basically, I have a class (that I don't want to modify) that is activated in a form like so:
var myEvent = new EventListener<KeyboardEvent/*or other type of event*/>((e) => {
///do stuff with event "e"
});
I want to make a function that makes a new event listener "dynamically", meaning based on a particular variable for the "event type" (forget about the function body for now, just assume they all have the same function body), like:
void makeEvent(Type eventType) {
var myEvent = new EventListener<eventType>((e) => {
///do stuff with event "e"
});
}
as many of you will know, as did those people who posted the above questions, that simple doing that will give a "variable used like a type" error, and it won't work, and many of them suggested using "reflection" to get around this, like (from Reflection To Execute Class With Generic Type):
ar instance = Activator.CreateInstance(implementation);
var results = this.GetType()
.GetMethod("CheckForMessages", BindingFlags.NonPublic | BindingFlags.Instance)
.MakeGenericMethod(interfaceUsesType)
.Invoke(this, null) as object[];
if(results.Count() > 0)
instance.GetType()
.GetMethod("DoThis")
.Invoke(instance, new object[] {results});
or (from Initializing a Generic variable from a C# Type Variable):
Animal a = MyFavoriteAnimal();
var contextType = typeof(EsbRepository<>).MakeGenericType(a.GetType());
dynamic context = Activator.CreateInstance(contextType);
context.DoAnimalStuff();
So these answers theoretically make a class definition, but in my case I need to do 2 things, #1: make the actual class of the EventListener, and #2 actually give the class a body (via the lambda expression above), so how can I do that with Activator.CreateInstance ? Or Is there any other way?
Basically I can't use a lambda in the object[], because its not an object, and if I use an Action of some kind that is an object, then I would need to pass in a generic type, and I'm back to where I started, for example I could theoretically do:
var myType = typeof(EventListener<>).MakeGenericType(eventType);
Activator.CreateInstance(myType, new object[] {
new Action<KeyboardEvent>(e => {})
});
which would compile, but then I'm back to where I started in the first place, because "KeyboardEvent" is itself what I need to change, and if I do:
Action<myDynamicTypeVariable>(e=>{})
I get the same "variable is used as type" error...
Isn't there just some kind of way to actually use a variable as a type?
Or is there a way to set the body of a function after the class instance has been formed?
Or how can I pass in a generic function as one of the object[] arguments without having to specify the type of the function and without using lambdas?
I'm asking this out of curiosity and I'm aware about other ways of doing so.
I was wondering, if some method is returning an object of some type and we can modify that object's property directly (on the fly - without taking it's reference into local variable).
Why do we need to take it's reference into local variable to change the object itself?
What logical difficulties can be there at compiler level which restrict programmer to do so.
See example code below:
static Demo StaticDemoInstance;
static void Main(string[] args)
{
//allowed: means I can directly modify property of static instance
// received from method
GetDemo().Name = "UpdateDemo";
//allowed: means I can get instance and overwrite it with other instance
// but not directly from method
Demo d = GetDemo();
d = new Demo("NewCreatedDemo", false);
//not allowed: means I can't do second step directly on method
// question:
// when I can update instance property without receiving instance on local variable
// what possible violation/difficulty (in compiler) will be there so it doesn't allow this
GetDemo() = new Demo("UpdatedDemoFromGetMeth", false);
}
static Demo GetDemo() => StaticDemoInstance ??
StaticDemoInstance = new Demo("StaticDemo", false);
You could always use a Ref return
Starting with C# 7.0, C# supports reference return values (ref
returns). A reference return value allows a method to return a
reference to a variable, rather than a value, back to a caller. The
caller can then choose to treat the returned variable as if it were
returned by value or by reference. The caller can create a new
variable that is itself a reference to the returned value, called a
ref local.
Limitations
There are some restrictions on the expression that a method can return
as a reference return value. Restrictions include:
The return value must have a lifetime that extends beyond the execution of the method. In other words, it cannot be a local variable
in the method that returns it. It can be an instance or static field
of a class, or it can be an argument passed to the method. Attempting
to return a local variable generates compiler error CS8168, "Cannot
return local 'obj' by reference because it is not a ref local."
The return value cannot be the literal null. Returning null generates compiler error CS8156, "An expression cannot be used in this
context because it may not be returned by reference."
A method with a ref return can return an alias to a variable whose value is currently the null (uninstantiated) value or a nullable type
for a value type.
The return value cannot be a constant, an enumeration member, the by-value return value from a property, or a method of a class or
struct. Violating this rule generates compiler error CS8156, "An
expression cannot be used in this context because it may not be
returned by reference."
A really contrived example and not what i recommend, however it does achieve your goals (academically)
Example
static Demo StaticDemoInstance;
...
static ref Demo GetDemo()
{
if (StaticDemoInstance == null)
StaticDemoInstance = new Demo("StaticDemo", false);
return ref StaticDemoInstance;
}
..
GetDemo() = new Demo("UpdatedDemoFromGetMeth", false);
Update
The use of it can be seen with further convoluted example and modifications
Exmaple
static Demo Test()
{
return StaticDemoInstance;
}
...
GetDemo() = new Demo("UpdatedDemoFromGetMeth", false);
var someObject = Test();
someObject= new Demo("Test", false);
Console.WriteLine(StaticDemoInstance.Name);
Console.WriteLine(someObject.Name);
Output
UpdatedDemoFromGetMeth
Test
The Test method (is not ref return) and only giving you a copy of the reference (for lack of better terminology), if you overwrite it, your static variable to StaticDemoInstance doesn't change
I read quite some articles about delegates, and yes, at first the syntax is confusing. I found this article the most useful. Example 2 makes it quite understandable how to use delegates. But I have this code given to me and have work with it:
public delegate bool IntPredicate(int x);
public delegate void IntAction(int x);
class IntList : List<int>
{
public IntList(params int[] elements) : base(elements)
{
}
public void Act(IntAction f)
{
foreach (int i in this)
{
f(i);
}
}
public IntList Filter(IntPredicate p)
{
IntList res = new IntList();
foreach (int i in this)
if (p(i))
res.Add(i);
return res;
}
}
Now, what confuses me here is the f and p variables in the Act and Filter functions. As in the tutorial, those functions seem to be normal, with normal type of their attributes, but here the attributes are of the delegate functions type and I get confusled.
Can you please enlighten me a bit on this matter?
A delegate is just a type. With the types you're used to (like int, string etc.), when you want to use them, you either use one that is in the framework or you declare your own. You can do exactly the same with delegates - either use a prebuilt one (like System.Action) or declare your own, which is what was done here.
So, in your code snippet, 3 types are declared:
public delegate bool IntPredicate(int x);
public delegate void IntAction(int x);
class IntList : List<int> { ... }
You'll notice that the delegate declarations are on the same level as the class declaration.
When you have a type (like your IntPredicate here), you can then use it for variables or function parameters. The questions now are: how do you set the value of the variable, and what do you do with it then?
With ordinary variables, you just pass in the value. Like this:
string text = "Hello world";
The principle is the same with delegates, but, of course, you have to pass in something that is of the delegate type or something that can be converted to it. You have several options:
Existing method
You can pass in a method, if its signature (that is, the return value and parameters) match those of the delegate. So, you could do this:
void WriteIntAction(int value)
{
Console.WriteLine(value);
}
/* then, in some other method */
IntList intList = new IntList(1,2,3);
intList.Act(WriteIntAction);
Anonymous method
There are several ways to create an anonymous method. I'm going to go with lambda expression, because that is simplest. If you've ever worked with any functional languages, this should be familiar.
IntList intList = new IntList(1,2,3);
intList.Act(x => Console.WriteLine(x));
So, after you have your variable set up with the method you need (whether existing or anonymous), you can simply use the delegate variable as you would any method. This is what this line does:
f(i);
Just be aware that delegate is a reference type, so the value of f here can be null, which will then throw an exception when you try to call a delegate.
TL;DR
A delegate is a type. You can use it in a variable or method parameter. You can pass a method in just using its name or you can create an anonymous method. You can then call the method you passed it by using the variable as you would a method.
You can read more online, for example here: http://msdn.microsoft.com/en-us/library/ms173171.aspx
A delegate type is, for all intents and purposes, just a function (or if you are a C++ user, akin to a function-pointer). In other words, you call them just as if they were a function, which is exactly what the sample code does.
f(i) calls the passed function with the i variable as its sole argument, just as it looks.
I have a function that wraps a call to one of my socket types. If there is an error, I want to be able to print a warning and retry. In the warning, I want to have the method name. However, it was declared as a lambda. Is this even possible?
How I call the function (assume in function called myMain):
SafeSocketCommand(() => this.mySocket.ReadCurrentBuffer());
Basic wrapping function:
protected TResult SafeSocketCommand<TResult>(Func<TResult> socketCommand)
{
TResult retValue = default(TResult);
try
{
retValue = socketCommand();
}
catch (PacketLost)
{
ReportToLogs("Timeout on command '" + socketCommand.Method.Name);
}
return retValue;
}
But socketCommand.Method.Name gives me the calling method (from the Stack Trace?) '< myMain >b__3' and I want the actual function being invoked by socketCommand (mySocket.ReadCurrentBuffer). Is it possible to get this information anywhere, or is it lost due to declaring in a lambda?
EDIT:
I should have mentioned that I use this particular calling convention so that I can use socket based commands of various signatures.
int i = SafeSocketCommand(() => this.mySocket.FunctionReturnsInt())
bool b = SafeSocketCommand(() => this.mySocket.FunctionReturnsBool(string s))
object o = SafeSocketCommand(() => this.mySocket.Complicated(string s, int i, bool b))
It also handles no return type signatures by overloading:
protected void SafeSocketCommand(Action socketCommand)
{
SafeSocketCommand(() => { socketCommand(); return 0; });
}
If you modify your SafeSocketCommand to accept an Expression<Func<TResult>> then you'll get access to an expression tree that represents the body of the lambda, from which you can access the ReadCurrentBuffer call directly.
However, if you do this, you're no longer dealing with a regular anonymous method; to actually call it you'll need to compile the expression tree to code. You may also need to be flexible as to what your code expects to appear inside the lambda's body.
No, because lambda's don't have names; they're anonymous functions. You could get the method name from the last stackframe, though:
new StackFrame(1).GetMethod().Name;
Func<TResult> is just a delegate. Rather than use a lambda, create a method that matches the signature of Func<TResult> and call that. That way, you'll have whatever name you want.
SafeSocketCommand(MyNewMethod);
...
public TResult MyNewMethod()
{
return this.mySocket.ReadCurrentBuffer();
}
In this case, you can simply this call instead. It'll be faster and smaller generated code too.
SafeSocketCommand(mySocket.ReadCurrentBuffer);
In general, the StackTrace of the Exception object contains the full information you are looking for, much more accurately than printing the method name, or you can use the TargetSite property for the name of the method that threw the exception.