I need to pass pointer to a function as a parameter. It looks like this:
void f(Action<String> a);
But what if caller knows which string will be used. And he's always knows it. Sure i can add one more parameter, but this is not cool.
Can i somehow create delegate with predefined parameter? Thanks.
EDIT:
As workaround i can do like that
void f(Action<String> a, String s)
{
a(s);
}
...
f(_delegate, "string");
As #Spo1ler commented, pass an Action instead of Action<string>:
void f(Action a)
{
a();
}
...
f(() => _delegate("string"));
Related
I am trying to learn Action delegate and lambda in C#.
So far I came to know that Action delegate encapsulates a method that does not have any parameter and returns void.
If we want to encapsulate a method having a parameter then we should use Action<T>. In the code which I am sharing, the method is having int parameter. And I am using Action delegate instead of Action<T>. Still I am able to invoke the method.
I am not able to understand this. Could anyone please explain the reason?
public static void Fourth(Action action)
{
Console.WriteLine("Fourth invoked");
action();
}
public static void Third(int x)
{
Console.WriteLine("Third invoked");
int result;
result = 3 + x;
Console.WriteLine(result);
}
Action a2 = () => Third(50);
Fourth(a2);
This line Action a2 = () => Third(50); creates a new parameter less method, which executes the Third() method.
If you want to assign the Third method to a2. You should write Action<int> a2 = Third;. Which will result in calling a2(50);
It's easy to get confused here.
a2 is not encapsulating the method Third. It uses an anonymous method declared via your lambda
() => Third(50);
This is converted by the compiler to a method in your class like that:
private static void SomeSpecialName() // so special that the name can't be used in C#, hence anonymous
{
Third(50);
}
and it is that SomeSpecialName() (having no arguments) method that a2 now refers to.
I have a bunch of methods that return List of GridTiles, for example GetTopNeighbour. I would like to be able to pass them to method AutoConnect using the GetNeighboursHandler delegate as a parameter.
public delegate List<GridTile> GetNeighboursHandler(GridTile c);
public List<GridTile> GetTopNeighbour(GridTile c)
{
//do stuff and return list
return null;
}
public GridTile AutoConnect(GridTile c, GetNeighboursHandler del)
{
List<GridTile> tempList = del(c);
// do stuff with the tempList
}
public void Test(GridTile c)
{
AutoConnect(c, GetTopNeighbour(c));
}
In the Test method I get the error: ... cannot convert ...Generic.List...to GetNeighboursHandler.
Have I completely misunderstood how delegates work?
You need to pass a delegate (which is an object that knows how to call the method, ie: it holds the reference of a method)
What you have done is passing the function result that you get after it's execution
GetTopNeighbour(c) returns a List<GridTile>, and you are passing this return value in your code here
AutoConnect(c, GetTopNeighbour(c));
Instead you should pass the reference to that method GetTopNeighbour
AutoConnect(c, GetTopNeighbour);
Refer these This is a tutorial and here's another one
You have to pass the method (or rather, method group) itself, instead of calling it:
AutoConnect(c, GetTopNeighbour);
You're passing the result of GetTopNeighbour(c), which is a List<GridTile>, as a parameter to AutoConnect.
Instead, you want to pass the MethodGroup to be converted to a delegate, like so:
AutoConnect(c, GetTopNeighbour);
It exist something like Action but which can encapsulate method with signature:
void SomeFunc(IDictionary<string,class>), I try solve this:
private void RefreshContactList()
{
var freshFriends = Service.GetAllFriends(Account);
new System.Action(RefreshContactsData(freshFriends)).OnUIThread();
}
private void RefreshContactsData(IEnumerable<KeyValuePair<string, UserInfo>> freshFriends)
{
//...
}
If I understand you correctly you can use generic Action delegate. You can write then:
Action<IDictionary> myAction; //with one parameter
Action<IDictionary, int> myAction2; //with two parameters
It's not really clear what you're trying to do. Your code tries to create a delegate incorrectly - you are passing in the return value of a method invocation:
new System.Action(RefreshContactsData(freshFriends))
instead of the method itself:
new System.Action(RefreshContactsData)
However, there would be no point in creating a delegate only to call it immediately - you could just as easily call the method directly. What does OnUIThread do? What are you trying to achieve?
You do not need Action, but Action<>:
new System.Action<IEnumerable<KeyValuePair<string, UserInfo>>>(RefreshContactsData).BeginInvoke(freshFriends, null, null);
You can use the Action<> type, which encapsulates a method taking a parameter, or if you need a return value, the Func and Func<> types. For example:
static void PrintHello()
{
Console.WriteLine("Hello world");
}
static void PrintMessage(string message)
{
Console.WriteLine("Hello " + message);
}
....
Action hello = new Action(PrintHello);
Action<string> message = new Action<string>(PrintMessage);
hello();
message("my world");
produces:
Hello world
Hello my world
Note how the action is created, just referencing the method that is encapsulated within, and then it's invoked, passing the required parameter.
First, I was reading some forums and the help in MSDN and all says that a delegate can't be overloaded.
Now, I want to have something like this:
public delegate void OneDelegate();
public delegate void OneDelegate(params object[] a);
public void DoNothing(params object[] a) {}
public void DoSomething() { /* do something */ }
private OneDelegate someFunction;
someFunction = new OneDelegate(DoSomething);
someFunction = new OneDelegate(DoNothing);
So, like you know, you CAN'T do this, because OneDelegate only refers to the first one and not the second one. But, is there a way for doing this? or something like that?
PS1: I want to have any number of OneDelegate declarations, not just one or two.
Imagine for a moment this was possible. Suppose I could have an overloaded delegate:
public delegate void OneDelegate(int i);
public delegate void OneDelegate(string s);
Now imagine I declare a variable of this type and then assign a function to it, for example:
OneDelegate myDelegate = StringMethod;
where StringMethod is declared thusly:
public void StringMethod(string s) { Console.WriteLine(s); }
Now you pass myDelegate to some other code, and that code does this:
myDelegate(47);
What do you expect to happen in this case? How can the runtime call StringMethod() with an integer argument?
If you really want a delegate that can take any set of parameters at all, then the only option is to have one with a params object[] array:
public delegate void OneDelegate(params object[] parameters);
But then you will have to assign to it a function that can actually handle any object array, for example:
public void MyMethod(params object[] parameters)
{
if (parameters == null || parameters.Length == 0)
throw new ArgumentException("No parameters specified.");
if (parameters.Length > 1)
throw new ArgumentException("Too many parameters specified.");
if (parameters[0] is int)
IntMethod((int) parameters[0]);
else if (parameters[0] is string)
StringMethod((string) parameters[0]);
else
throw new ArgumentException("Unsupported parameter type.");
}
As you can see, this gets messy real quick. Therefore, I submit to you that if you need such a delegate, you have probably made a mistake somewhere in your architectural design. Identify this flaw and fix the design before you proceed with the implementation, as otherwise the maintainability of your code will suffer.
The Action class "does this". It's a delegate with templates, so you can have a delegate like this:
public delegate void D<T>(params T[] arg);
func() {
D<object> d1;
}
This is probably as close as you are going to get, i.e. you need a template type as a parameter.
Edit: Based on comments I guess you are after passing a delegate to another function. You can accomplish it by passing along the arguments as well. Unfortunately you cannot do this without the use of a params parameter to fire.
public void bar() {
D<string> d = ...;
fire(d, "first", "second");
fire(d); // also works
}
public void fire<T>(D<T> f, params T[] args) {
f(args);
}
In the code below I pass method B as an action to be perfomed on on the objects in the IterateObjects method.
I would like to ask whether I can explicitly declare the method in the argument instead of passing it by name, something like this:
a.IterateObjects(delegate void(string s){//method body}) Its not correct but I am sure I have seen something like that working. Could you please advise? Thank you
DelTest a = new DelTest(); //class with method IterateObjects
a.IterateObjects(B) //HERE
private void B(string a)
{
listBox1.Items.Add(a);
}
//another class ....
public void IterateObjects(Action<string> akce)
{
foreach(string a in list)
{
akce(a);
}
}
Yes you can use a lambda like so :
a.IterateObjects ( x => listBox1.Items.Add(x) );
delegate void MyFunctionDelegate(string a);
public void Main()
{
iterateObjects (delegate(string a){/*do something*/});
}
public void IterateObjects(MyFunctionDelegate akce)
{
foreach(string a in list)
{
akce(a);
}
}
http://msdn.microsoft.com/en-us/library/900fyy8e%28VS.80%29.aspx
that's it :)
You can declare function B as anonymous function at the point of calling, through a lambda expression.
You can use a lambda expression:
a.IterateObjects((string s) => listBox1.Items.Add(s))