I have the below code snippet in my project. I am new to lambda expressions. I have some idea about it and also
started using it. But I do not understand how the below code is working. Specially,
NotifyIntrenal( notification, callback, changedTypes => ..
Now here changedTypes is one of the parameter for method NotifyIntrenal. We derive its value using an anomymous method.
If I see the code, since I do not assign any value to changedTypes, so as per my understanding the code if (changedTypes == null) should
always be true. But this is not the case when I debug.
Can someone explain me how does this works here?
private void Notify( Notification notification )
{
var nameDto = GetNameDto();
foreach (var subscription in _subscriptionsDictionary)
{
var callback = subscription.Key;
var subscribedTypes = subscription.Value;
NotifyIntrenal( notification, callback, changedTypes =>
{
if (changedTypes == null)
return subscribedTypes;
if (!changedTypes.Any())
return subscribedTypes;
return changedTypes.Intersect(subscribedTypes);
}, nameDto);
}
}
Thanks & Regards
changedTypes is not an argument to NotifyInternal. It is the parameter for the anonymous method.
This whole method is the argument for NotifyInternal.
The code inside that lambda is not executed at this point. It will only be executed if some line in NotifyInternal calls it. So there has to be code line in NotifyInternal executing the anonymous method:
void NotifyInternal(Notification notification, Callback callback, Func<IEnumerable<Type>, IEnumerable<Type>> function, string nameDto)
{
// ... some code
// execute the lambda
var result = function(mychangedtypesvariable);
// ... more code
}
Only then the code inside the lambda is executed, using the pass argument (mychangedtypesvariable in that example). So if this will be null you cannot decide from the snippet you see.
changedTypes is just a paremeter for your anonymous method, not for NotifyIntrenal. The latter however calls that anonymous method and fills the parameter (if required) appropriately. In your case the anonymous method expects an IEnumerable<MyType> and returns an IEnumerable<MyType>.
NotifyIntrenal(string arg1, string arg2, Func<IEnumerable<MyType>, IEnumerable<MyType>> func) {
// do something
var list = new List<MyType> { ...}
// execute the delegate with the list
IEnumerable<MyType> result = func(list);
}
So actually changedTypes is provided by NotifyIntrenal, not given to it. How you create that argument within the method is up to you.
I have the following code (removed unrelated)
//top of class declaration
private delegate void UpdateFormElements(string status, bool addEmptyRow);
//inside a function in my class
if(lboImages.InvokeRequired)
{
lboImages.Invoke((UpdateFormElements)delegate { UpdateListBox("some text", true); });
}
private void UpdateListBox(string line, bool addEmptyRow)
{
lboImages.Items.Add(line);
if (addEmptyRow)
{
lboImages.Items.Add("");
}
}
Basically I'm trying to pass two parameters to the UpdateListBox function to test whether to add an empty line or not to my listbox, but I am getting the error in the title. I have tried putting the two values in an object[] but it doesn't seem to change anything as I still get the error.
I'm still new to using threads so not really sure where I'm going wrong here.
It's not clear why you're trying to use an anonymous method here. The problem is that you're creating a delegate type with two parameters, but you're not passing arguments (values for those parameters) into Invoke.
I suspect you just want:
lboImages.Invoke((UpdateFormElements) UpdateListBox, "some text", true));
That uses a method group conversion to create an UpdateFormElements delegate, and provides it the two arguments it needs.
Alternatively, you could just use a lambda expression:
MethodInvoker invoker = () => UpdateListBox(line, addEmptyRow);
lboImages.Invoke(invoker);
I have a function with a signature like so
private void FunkA(string eventName, Action action) {}
private void FunkB() {}
that I obtain though reflection. The value for action is also obtained through reflection so in my code I end up having to find a way to pass a 'MethodInfo' as a parameter into an invoke.
MethodInfo miForFunkA;
MethodInfo miForFunkB;
miForFunkA.Invoke(sourceOfFunkA, new [] {
methodInfo.Name,
Delegate.CreateDelegate(typeof(Action), miForFunkB)
});
The issue is I cant create a parameter list that has string and delegate types.
How should this be passed?
You should be to specify the array type explicitly:
miForFunkA.Invoke(sourceOfFunkA, new object[] {
methodInfo.Name,
Delegate.CreateDelegate(typeof(Action), miForFunkB)
});
If that doesn't address your question, you should edit your question so that it's clearer about what you're trying to do, declarations of all variables involved, what code you have now, what it does, and how that's different from what you want to do.
Is it possible to make a variable, and assign a line of code to it, such as:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... so when I use the variable, it will execute the line of code.
You could assign it to an Action like this:
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
Then call it:
ButtonClicked();
For completeness (in regards to the various comments)...
As Erik stated, you could execute multiple lines of code:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
As Tim stated, you could omit the Action keyword
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
To address KRyan's comment, regarding the empty parentheses, that represents the list of parameters you want to be able to send to the Action (in this case, none).
If, for instance, you wanted to specify the message to show, you could add "message" as a parameter (note that I changed Action to Action<string> in order to specify a single string parameter):
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
In your case, you want to use a delegate.
Let's see how a delegate works and how we can get to an easier form by understanding its concept:
// Create a normal function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
You see, the delegate takes the form of a normal function but without any arguments (It could take any amount of arguments just like any other method, but for the sake of simplicity, it doesn't).
Now, let's use what we have; we will define the delegate just as we define any other variable:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
We basically created a new variable called ButtonClicked, that has a type of ButtonClick (which is a delegate) and that when used, will execute the method in the OnButtonClick() method.
To use it we simply call: ButtonClicked();
So the whole code would be:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
From here, we can move to lambda expressions and see how they could be useful in your situation:
There are many delegates already defined by .NET libraries, with some like Action, which do not accept any parameter and does no return a value. It is defined as public delegate void Action();
You can always use it to your needs instead of the need of defining a new delegate every time. In the previous context for example, you could had just written
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
which would had done the same.
Now that you saw different ways of how to use delegates, let's use our first lambda expression. Lambda expressions are anonymous functions; so, they are normal functions but without a name. They are of those forms:
x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");
In our case, we do not have any parameters so we will use the last expression. We can use this just as the OnButtonClick function, but we get the advantage of not having a named function. We can instead do something like this:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
or even easier,
Action ButtonClicked = () => MessageBox.Show("Hello World!");
then simply call ButtonClicked(); Of course you can also have multi-lines of code, but I do not want to confuse you more. It would look like this though:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
You could also play around, for example, you can execute a function like this:
new Action(() => MessageBox.Show("Hello World!"))();
Sorry for the long post, hope it was not too confusing :)
EDIT: I forgot to mention that an alternate form which, even though not often used, could make lambda expressions easier to understand:
new Action(delegate() {
Console.WriteLine("I am parameterless");
})();
Also, using generics:
// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.
new Action<string>(delegate(string x) {
Console.WriteLine(x);
})("I am a string parameter!");
In turn you could use lambda expressions, but you do not need (but might in some cases) to define the type of the parameter, for example, the code above could simply be written as:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
or:
new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");
EDIT2:
Action<string> is a representation of public void delegate Action(string obj);
Action<string,string> is a representation of public void delegate Action(string obj, string obj2);
In general, Action<T> is a representation of public void delegate Action<T>(T obj);
EDIT3:
I know the post has been here for a while, but I think this is really cool to not mention:
You can do this, which is mostly related to your question:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
or simply:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
The Lazy class is specifically designed to represent a value that won't be computed until you ask for it. You construct it by providing a method that defines how it should be constructed, but it will handle executing that method no more than once (even in the face of multiple threads requesting the value) and simply returning the already constructed value for any additional requests:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
The way I'm reading your question, this is in the context of GUI controls?
If this is in WPF, take a look at the "right" way to handle commands from controls:
http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
...but that can be a pain and overkill. For a simpler general case, you might be looking for an event handler, like:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
That event handler can be handled a variety of ways. The above example uses an anonymous function, but you could also do:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
...just like you were asking, with a function (or here, "Action", since it returns void) assigned as a variable.
You can assign C# code to a variable, compiling it at runtime and run the code:
Write your code:
// Assign C# code to the code variable.
string code = #"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ #"
}
}
}
";
Create the provider and parameters of the compiler:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Define parameters of the compiler:
// Reference to System.Drawing library
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
// True - memory generation, false - external file generation
parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = true;
Compile assembly:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Check errors:
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Get assembly, type and the Main method:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Run it:
main.Invoke(null, null);
Reference:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
I want to create a method like this:
private static void AddOrAppend<K>(this Dictionary<K, MulticastDelegate> firstList, K key, MulticastDelegate newFunc)
{
if (!firstList.ContainsKey(key))
{
firstList.Add(key, newFunc);
}
else
{
firstList[key] += newFunc; // this line fails
}
}
But this fails because it says you can't add multicast delegates. Is there something I'm missing? I thought the delegate keyword was just shorthand for a class which inherits from MulticastDelegate.
firstList[key] = (MulticastDelegate)Delegate.Combine(firstList[key],newFunc);
with test:
var data = new Dictionary<int, MulticastDelegate>();
Action action1 = () => Console.WriteLine("abc");
Action action2 = () => Console.WriteLine("def");
data.AddOrAppend(1, action1);
data.AddOrAppend(1, action2);
data[1].DynamicInvoke();
(which works)
But tbh, Just use Delegate in place of MulticastDelegate; this is largely a hangover from something that never really worked. Or better; a specific type of delegate (perhaps Action).