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);
Related
I'm working with a project for thesis-work for a company and I'm having some difficulties understanding some code.
In their code they have a line like this
_subscriber.StartSubscribing(_messageHandler.HandleMessage);
where _subscriber is function is defined
public override void StartSubscribing(Action<QueueItem> messageHandlerMethod);
And _messageHandler is defined
public void HandleMessage(QueueItem message)
{
//Do code here
}
How come at the top the messageHandler don't need a parameter for HandleMessage?
E.I
_subscriber.StartSubscribing(_messageHandler.HandleMessage(QueueItem));
Because you're not actually executing the method HandleMessage (which would happen if you had parentheses and a parameter). You are passing it as a reference to StartSubscribing which expects a method with a specified signature (void return, one parameter of type QueueItem)
Action<T> is a generic delegate, this particular version is a delegate which specifies no return (void) and a single parameter of type T (or QueueItem in your example)
In fact, it is the method StartSubscribing (or perhaps the class it belongs to) which is likely to provide the instance of QueueItem - perhaps something like this:
public override void StartSubscribing(Action<QueueItem> messageHandlerMethod)
{
// do something to get/create a QueueItem
QueueItem item = SomeMagic();
// pass it back to the passed in delegate
messageHandlerMethod(item);
}
With _subscriber.StartSubscribing(_messageHandler.HandleMessage) you are using a more direct way for _subscriber.StartSubscribing(msg => _messageHandler.HandleMessage(msg)).
So it does need a parameter.
Here's my attempt at calling an existing generic method with a type argument. 'Strongly typed reflection' may not be a suitable term, but it basically means finding and invoking the reflected method without using a name string.
public class TestClass
{
public static void Test(Type type)
{
InvokeTestMethodWithType(type);
}
private void Test<T>() { ... }
private static void InvokeTestMethodWithType(Type type)
{
// This doesn't compile! - can I find Test<> using this approach?
Expression<Func<TestClass, Action>> ex = x => x.Test<>;
// invoke it
((MethodCallExpression)ex.Body).Method.MakeGenericMethod(type).Invoke(new TestClass(), null);
}
}
Sample call would end up call the private Test().
TestClass.Test(typeof(Foo))
As you can see, I'm struggling with the expression and not entirely sure if it can be executed in this manner.
Do I have to dummy invoke the action in the expression like this post?
x => x.Test<object>()
The trick I use is simple: pass a fake generic type argument:
Expression<Func<TestClass, WhateverTestReturns>> ex = x => x.Test<string>();
// invoke it
((MethodCallExpression)ex.Body)
.Method
.GetGenericMethodDefinition()
.MakeGenericMethod(type)
.Invoke(new TestClass(), null);
The method call expression will then contain a method info for Test<string>(), but you can easily use GetGenericMethodDefinition to remove the generic argument, and then MakeGenericMethod to put a different one back in its place.
You don't even need to use Expression in a case like this - simply cast TestClass.Test<string> to a delegate, and you'll have a Method property that gives you the same method info.
I try really hard to not let visual studio allow me to fix code without really understanding what's going on. But here it helped me solve a problem and I want to make sure that I understand what's going on before continuing.
Reading the documentation makes me think I'm passing a method as an argument? Why must I have the () at the end of exposureIterator() as opposed to just exposureIterator when passing it as an argument (the first Bar method below is the correct one)? I feel like I must be having an epic brain fart or missing something really important. I really hope it's the former...
Thanks for the help :)
public void Foo (Ienumerable iterator)
{
...
}
public static System.Collections.IEnumerable exposureIterator()
{
for (int i = 20; i < 55; i += 5)
{
yield return i.ToString();
}
}
public void Bar()
{
Foo(exposureIterator());
}
VS
public void Bar()
{
Foo(exposureIterator);
}
EDIT: Just realized. System.Collections.IEnumerable is simply a return type and it being referenced like that is what confused me. Hurr durrr. Thanks again for the clarification everyone :)
You are passing the result of the method as an argument. The () means that there's a function call, and that is evaluated first before the results are set to your Foo() method. When you exclude the () you are, in fact, passing the method as an argument. This is valid in some cases, but only when the parameter type is a delegate type (read up on delegates here if you aren't sure what I'm talking about: http://msdn.microsoft.com/en-us/library/ms173171(v=vs.90).aspx).
You can think of your code like this:
public void Bar() {
// call exposureIterator method and store result in a local variable
IEnumerable result = exposureIterator();
// pass local variable containing IEnumerable object to your method
Foo(result);
}
You are not actually passing a method, you are passing the result of a method.
public void Foo (Ienumerable iterator)
{
...
}
Foo(IEnumerable iterator) expects an IEnumerable object.
exposeIterator() returns an IEnumerable object. So when you call:
public void Bar()
{
Foo(exposureIterator());
}
You are actually passing the result of exposeIterator(), which is an IEnumerable. It is equivalent to:
public void Bar()
{
IEnumerator enumerator = exposeEnumerator;
Foo(enumerator);
}
You should also be aware that in certain instances, a method signature may actually ask for a method reference as an argument. In those cases, you would indeed drop the () to pass the argument.
To call exposureIterator() you need the () to call the method if it had parameters the () would specify the start and end of those parameters.
You're passing the IEnumerable returned from exposureIterator() into Foo in the 1st instance; so it is actually executing exposureIterator before calling Foo; in other words you're doing this:
public void Bar()
{
IEnumerable x = exposureIterator();
Foo(x);
}
Consider class
class FirstClass
{
//Some fields, ctors and methods
...
public event Action Test
{
add
{
var method = value.Method;
var parameters = method.GetParameters (); //Count == 1
// (1)
//I don't know anything about value so I think I can pass null as argument list because it's Action, not Action<T>
//And we get Reflection.TargetParameterCountException here.
method.Invoke (value.Target, null);
//Instead of calling Invoke as done above, we should call it like that:
// (2)
method.Invoke (value.Target, new object[] { null });
//But since it's Action, we should be able to call it with (1) not with (2)
}
remove
{
...
}
}
}
And another class
class SecondClass
{
public void TestMethod (Action action = null)
{
...
}
public void OtherMethod ()
{
var a = new FirstClass ();
a.Test += TestMethod;
}
}
IMHO: adding method with default arguments to delegate without parameters shouldn't be allowed at type system level.
Why it is allowed?
P.S. You could do this not only in add { } accessor but in any other place, code above is just example.
This should not compile.
Delegate Action has a signate of zero parameters, and no return value:
public delegate void Action();
So only methods with zero parameters and not return values can be assigned to it. Your second class SecondClass.TestMethod does have an argument of type Action (to make it all confusing, I guess ;)). So that method would be compatible with another Action delegate (where T = Action):
public delegate void Action<T>();
If you even do try to manage to call FirstClass.Test.Add, and you try to make the two Invoke-calls, the first one should fail.
Why? The method is a MethodInfo of SecondClass.TestMethod. This method requires at least one parameter. This parameter must be inside the object-array given to the invoke method. But, in your first call, you do not have an object-array; your object array is set to null. And an object-array set to null cannot hold anything, not even 0 elements, let alone 1 element having null.
The second Invoke does have an object-array with one element, having null.
I want to have a library that will have a function in it that accepts an object for it's parameter.
With this object I want to be able to call a specified function when X is finished. The function that will be called is to be specified by the caller, and X will be done and monitored by the library.
How can I do this?
For reference I'm using C# and .NET 3.5
Two options for you:
Have the function accept a delegate (Action for a callback that doesn't return anything, Func for one that does) and use an anonymous delegate or Lambda Expression when calling it.
Use an interface
Using a delegate/lambda
public static void DoWork(Action processAction)
{
// do work
if (processAction != null)
processAction();
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate() { Console.WriteLine("Completed"); });
// using Lambda
DoWork(() => Console.WriteLine("Completed"));
}
If your callback needs to have something passed to it, you can use a type parameter on Action:
public static void DoWork(Action<string> processAction)
{
// do work
if (processAction != null)
processAction("this is the string");
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate(string str) { Console.WriteLine(str); });
// using Lambda
DoWork((str) => Console.WriteLine(str));
}
If it needs multiple arguments, you can add more type parameters to Action. If you need a return type, as mentioned use Func and make the return type the last type parameter (Func<string, int> is a function accepting a string and returning an int.)
More about delegates here.
Using an interface
public interface IObjectWithX
{
void X();
}
public class MyObjectWithX : IObjectWithX
{
public void X()
{
// do something
}
}
public class ActionClass
{
public static void DoWork(IObjectWithX handlerObject)
{
// do work
handlerObject.X();
}
}
public static void Main()
{
var obj = new MyObjectWithX()
ActionClass.DoWork(obj);
}
Sounds like a perfect recipe for delegates - in particular, callbacks with delegates are exactly how this is handled in the asynchronous pattern in .NET.
The caller would usually pass you some state and a delegate, and you store both of them in whatever context you've got, then call the delegate passing it the state and whatever result you might have.
You could either make the state just object or potentially use a generic delegate and take state of the appropriate type, e.g.
public delegate void Callback<T>(T state, OperationResult result)
Then:
public void DoSomeOperation(int otherParameterForWhateverReason,
Callback<T> callback, T state)
As you're using .NET 3.5 you might want to use the existing Func<...> and Action<...>
delegate types, but you may find it makes it clearer to declare your own. (The name may make it clearer what you're using it for.)
The object in question will need to implement an interface provided by you. Take the interface as a parameter, and then you can call any method that the interface exposes. Otherwise you have no way of knowing what the object is capable of. That, or you could take a delegate as a parameter and call that.
Is there a reason not to have your library provide a public event to be fired when the operation is complete? Then the caller could just register to handle the event and you don't have to worry about passing around objects or delegates.
The object implementing an interface you have provided would work, but it seems to be more the Java approach than the .NET approach. Events seem a bit cleaner to me.
You can use System.Action available in C#.NET for callback functions. Please check this sample example:
//Say you are calling some FUNC1 that has the tight while loop and you need to
//get updates on what percentage the updates have been done.
private void ExecuteUpdates()
{
Func1(Info => { lblUpdInfo.Text = Info; });
}
//Now Func1 would keep calling back the Action specified in the argument
//This System.Action can be returned for any type by passing the Type as the template.
//This example is returning string.
private void Func1(System.Action<string> UpdateInfo)
{
int nCount = 0;
while (nCount < 100)
{
nCount++;
if (UpdateInfo != null) UpdateInfo("Counter: " + nCount.ToString());
//System.Threading.Thread.Sleep(1000);
}
}