I'm trying to create a delegate that will return a delegate. I then want to invoke this delegate, and also invoke the returned inner delegate. My question is: Why is this causing an error? And how to I change this code to accomplish what I'm trying to do?
The error message is 'Method name expected'.
delegate string del();
delegate Delegate nestedDel();
public static void main()
{
nestedDel myNestedDel = () =>
{
del myInnerDel = () => { return "inside"; };
return myInnerDel;
};
Delegate k = myNestedDel();
k(); // Error!!!
}
In short, you've messed up the types. One of the delegates should return the other one, so its return type should simply be the type of the other delegate. In your code example:
delegate string del();
delegate Delegate nestedDel();
you are in fact returning a delegate, but Delegate or MulticastDelegate are just infrastructure base classes and are not invocable directly. By using these classes you're losing information about list of parameters and return values, so simple call() operator cannot work. As Lee mentioned in comments, you could do it by k.DynamicInvoke() but that's.. overkill. Just use a proper type name instead of Delegate.
Working example:
delegate string InnerDel();
delegate InnerDel OuterDel(); // this one returns an instance of Inner delegate
public static void Main()
{
OuterDel myOuterDelegate = () =>
{
InnerDel myInnerDel = () => { return "inside"; };
return myInnerDel;
};
InnerDel k = myOuterDelegate();
k();
}
Personally, I like Func/Actions more than defining my own delegate classes... at least as long as they have at most few parameters. In terms of func/action it would look like this:
public static void Main()
{
Func<Func<string>> myOuterDelegate = () =>
{
Func<string> myInnerDel = () => { return "inside"; };
return myInnerDel;
};
var k = myOuterDelegate();
k();
}
or even..
public static void Main()
{
Func<Func<string>> myOuterDelegate = () => () => { return "inside"; };
var k = myOuterDelegate();
k();
}
Your error is because instances of the Delegate type cannot be invoked with the function call syntax i.e. as k();.
You can call it using DynamicInvoke:
string s = (string)k.DynamicInvoke();
obviously this is prone to runtime errors so a better approach would be to change the return type of nestedDel e.g.
delegate Func<string> nestedDel();
nestedDel myNestedDel = () =>
{
Func<string> myInnerDel = () => { return "inside"; };
return myInnerDel;
};
stringk = myNestedDel();
Related
Using the new async/await model it's fairly straightforward to generate a Task that is completed when an event fires; you just need to follow this pattern:
public class MyClass
{
public event Action OnCompletion;
}
public static Task FromEvent(MyClass obj)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
obj.OnCompletion += () =>
{
tcs.SetResult(null);
};
return tcs.Task;
}
This then allows:
await FromEvent(new MyClass());
The problem is that you need to create a new FromEvent method for every event in every class that you would like to await on. That could get really large really quick, and it's mostly just boilerplate code anyway.
Ideally I would like to be able to do something like this:
await FromEvent(new MyClass().OnCompletion);
Then I could re-use the same FromEvent method for any event on any instance. I've spent some time trying to create such a method, and there are a number of snags. For the code above it will generate the following error:
The event 'Namespace.MyClass.OnCompletion' can only appear on the left hand side of += or -=
As far as I can tell, there won't ever be a way of passing the event like this through code.
So, the next best thing seemed to be trying to pass the event name as a string:
await FromEvent(new MyClass(), "OnCompletion");
It's not as ideal; you don't get intellisense and would get a runtime error if the event doesn't exist for that type, but it could still be more useful than tons of FromEvent methods.
So it's easy enough to use reflection and GetEvent(eventName) to get the EventInfo object. The next problem is that the delegate of that event isn't known (and needs to be able to vary) at runtime. That makes adding an event handler hard, because we need to dynamically create a method at runtime, matching a given signature (but ignoring all parameters) that accesses a TaskCompletionSource that we already have and sets its result.
Fortunately I found this link which contains instructions on how to do [almost] exactly that via Reflection.Emit. Now the problem is that we need to emit IL, and I have no idea how to access the tcs instance that I have.
Below is the progress that I've made towards finishing this:
public static Task FromEvent<T>(this T obj, string eventName)
{
var tcs = new TaskCompletionSource<object>();
var eventInfo = obj.GetType().GetEvent(eventName);
Type eventDelegate = eventInfo.EventHandlerType;
Type[] parameterTypes = GetDelegateParameterTypes(eventDelegate);
DynamicMethod handler = new DynamicMethod("unnamed", null, parameterTypes);
ILGenerator ilgen = handler.GetILGenerator();
//TODO ilgen.Emit calls go here
Delegate dEmitted = handler.CreateDelegate(eventDelegate);
eventInfo.AddEventHandler(obj, dEmitted);
return tcs.Task;
}
What IL could I possibly emit that would allow me to set the result of the TaskCompletionSource? Or, alternatively, is there another approach to creating a method that returns a Task for any arbitrary event from an arbitrary type?
Here you go:
internal class TaskCompletionSourceHolder
{
private readonly TaskCompletionSource<object[]> m_tcs;
internal object Target { get; set; }
internal EventInfo EventInfo { get; set; }
internal Delegate Delegate { get; set; }
internal TaskCompletionSourceHolder(TaskCompletionSource<object[]> tsc)
{
m_tcs = tsc;
}
private void SetResult(params object[] args)
{
// this method will be called from emitted IL
// so we can set result here, unsubscribe from the event
// or do whatever we want.
// object[] args will contain arguments
// passed to the event handler
m_tcs.SetResult(args);
EventInfo.RemoveEventHandler(Target, Delegate);
}
}
public static class ExtensionMethods
{
private static Dictionary<Type, DynamicMethod> s_emittedHandlers =
new Dictionary<Type, DynamicMethod>();
private static void GetDelegateParameterAndReturnTypes(Type delegateType,
out List<Type> parameterTypes, out Type returnType)
{
if (delegateType.BaseType != typeof(MulticastDelegate))
throw new ArgumentException("delegateType is not a delegate");
MethodInfo invoke = delegateType.GetMethod("Invoke");
if (invoke == null)
throw new ArgumentException("delegateType is not a delegate.");
ParameterInfo[] parameters = invoke.GetParameters();
parameterTypes = new List<Type>(parameters.Length);
for (int i = 0; i < parameters.Length; i++)
parameterTypes.Add(parameters[i].ParameterType);
returnType = invoke.ReturnType;
}
public static Task<object[]> FromEvent<T>(this T obj, string eventName)
{
var tcs = new TaskCompletionSource<object[]>();
var tcsh = new TaskCompletionSourceHolder(tcs);
EventInfo eventInfo = obj.GetType().GetEvent(eventName);
Type eventDelegateType = eventInfo.EventHandlerType;
DynamicMethod handler;
if (!s_emittedHandlers.TryGetValue(eventDelegateType, out handler))
{
Type returnType;
List<Type> parameterTypes;
GetDelegateParameterAndReturnTypes(eventDelegateType,
out parameterTypes, out returnType);
if (returnType != typeof(void))
throw new NotSupportedException();
Type tcshType = tcsh.GetType();
MethodInfo setResultMethodInfo = tcshType.GetMethod(
"SetResult", BindingFlags.NonPublic | BindingFlags.Instance);
// I'm going to create an instance-like method
// so, first argument must an instance itself
// i.e. TaskCompletionSourceHolder *this*
parameterTypes.Insert(0, tcshType);
Type[] parameterTypesAr = parameterTypes.ToArray();
handler = new DynamicMethod("unnamed",
returnType, parameterTypesAr, tcshType);
ILGenerator ilgen = handler.GetILGenerator();
// declare local variable of type object[]
LocalBuilder arr = ilgen.DeclareLocal(typeof(object[]));
// push array's size onto the stack
ilgen.Emit(OpCodes.Ldc_I4, parameterTypesAr.Length - 1);
// create an object array of the given size
ilgen.Emit(OpCodes.Newarr, typeof(object));
// and store it in the local variable
ilgen.Emit(OpCodes.Stloc, arr);
// iterate thru all arguments except the zero one (i.e. *this*)
// and store them to the array
for (int i = 1; i < parameterTypesAr.Length; i++)
{
// push the array onto the stack
ilgen.Emit(OpCodes.Ldloc, arr);
// push the argument's index onto the stack
ilgen.Emit(OpCodes.Ldc_I4, i - 1);
// push the argument onto the stack
ilgen.Emit(OpCodes.Ldarg, i);
// check if it is of a value type
// and perform boxing if necessary
if (parameterTypesAr[i].IsValueType)
ilgen.Emit(OpCodes.Box, parameterTypesAr[i]);
// store the value to the argument's array
ilgen.Emit(OpCodes.Stelem, typeof(object));
}
// load zero-argument (i.e. *this*) onto the stack
ilgen.Emit(OpCodes.Ldarg_0);
// load the array onto the stack
ilgen.Emit(OpCodes.Ldloc, arr);
// call this.SetResult(arr);
ilgen.Emit(OpCodes.Call, setResultMethodInfo);
// and return
ilgen.Emit(OpCodes.Ret);
s_emittedHandlers.Add(eventDelegateType, handler);
}
Delegate dEmitted = handler.CreateDelegate(eventDelegateType, tcsh);
tcsh.Target = obj;
tcsh.EventInfo = eventInfo;
tcsh.Delegate = dEmitted;
eventInfo.AddEventHandler(obj, dEmitted);
return tcs.Task;
}
}
This code will work for almost all events that return void (regardless of the parameter list).
It can be improved to support any return values if necessary.
You can see the difference between Dax's and mine methods below:
static async void Run() {
object[] result = await new MyClass().FromEvent("Fired");
Console.WriteLine(string.Join(", ", result.Select(arg =>
arg.ToString()).ToArray())); // 123, abcd
}
public class MyClass {
public delegate void TwoThings(int x, string y);
public MyClass() {
new Thread(() => {
Thread.Sleep(1000);
Fired(123, "abcd");
}).Start();
}
public event TwoThings Fired;
}
Briefly, my code supports really any kind of delegate type. You shouldn't (and don't need to) specify it explicitly like TaskFromEvent<int, string>.
This will give you what you need without needing to do any ilgen, and way simpler. It works with any kind of event delegates; you just have to create a different handler for each number of parameters in your event delegate. Below are the handlers you'd need for 0..2, which should be the vast majority of your use cases. Extending to 3 and above is a simple copy and paste from the 2-parameter method.
This is also more powerful than the ilgen method because you can use any values created by the event in your async pattern.
// Empty events (Action style)
static Task TaskFromEvent(object target, string eventName) {
var addMethod = target.GetType().GetEvent(eventName).GetAddMethod();
var delegateType = addMethod.GetParameters()[0].ParameterType;
var tcs = new TaskCompletionSource<object>();
var resultSetter = (Action)(() => tcs.SetResult(null));
var d = Delegate.CreateDelegate(delegateType, resultSetter, "Invoke");
addMethod.Invoke(target, new object[] { d });
return tcs.Task;
}
// One-value events (Action<T> style)
static Task<T> TaskFromEvent<T>(object target, string eventName) {
var addMethod = target.GetType().GetEvent(eventName).GetAddMethod();
var delegateType = addMethod.GetParameters()[0].ParameterType;
var tcs = new TaskCompletionSource<T>();
var resultSetter = (Action<T>)tcs.SetResult;
var d = Delegate.CreateDelegate(delegateType, resultSetter, "Invoke");
addMethod.Invoke(target, new object[] { d });
return tcs.Task;
}
// Two-value events (Action<T1, T2> or EventHandler style)
static Task<Tuple<T1, T2>> TaskFromEvent<T1, T2>(object target, string eventName) {
var addMethod = target.GetType().GetEvent(eventName).GetAddMethod();
var delegateType = addMethod.GetParameters()[0].ParameterType;
var tcs = new TaskCompletionSource<Tuple<T1, T2>>();
var resultSetter = (Action<T1, T2>)((t1, t2) => tcs.SetResult(Tuple.Create(t1, t2)));
var d = Delegate.CreateDelegate(delegateType, resultSetter, "Invoke");
addMethod.Invoke(target, new object[] { d });
return tcs.Task;
}
Use would be like this. As you can see, even though the event is defined in a custom delegate, it still works. And you can capture the evented values as a tuple.
static async void Run() {
var result = await TaskFromEvent<int, string>(new MyClass(), "Fired");
Console.WriteLine(result); // (123, "abcd")
}
public class MyClass {
public delegate void TwoThings(int x, string y);
public MyClass() {
new Thread(() => {
Thread.Sleep(1000);
Fired(123, "abcd");
}).Start();
}
public event TwoThings Fired;
}
Here's a helper function that'll allow you to write the TaskFromEvent functions in just one line each, if the above three methods are too much copy-and-paste for your preferences. Credit has to be given to max for simplifying what I had originally.
If you're willing to have one method per delegate type, you can do something like:
Task FromEvent(Action<Action> add)
{
var tcs = new TaskCompletionSource<bool>();
add(() => tcs.SetResult(true));
return tcs.Task;
}
You would use it like:
await FromEvent(x => new MyClass().OnCompletion += x);
Be aware that this way you never unsubscribe from the event, that may or may not be a problem for you.
If you're using generic delegates, one method per each generic type is enough, you don't need one for each concrete type:
Task<T> FromEvent<T>(Action<Action<T>> add)
{
var tcs = new TaskCompletionSource<T>();
add(x => tcs.SetResult(x));
return tcs.Task;
}
Although type inference doesn't work with that, you have to explicitly specify the type parameter (assuming the type of OnCompletion is Action<string> here):
string s = await FromEvent<string>(x => c.OnCompletion += x);
I faced this problem by trying to write GetAwaiter extension method for System.Action, forgetting that System.Action is immutable and by passing it as an argument you make a copy. However, you do not make a copy if you pass it with ref keyword, thus:
public static class AwaitExtensions
{
public static Task FromEvent(ref Action action)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
action += () => tcs.SetResult(null);
return tcs.Task;
}
}
Usage:
await AwaitExtensions.FromEvent(ref OnActionFinished);
Note: TCS listener remain subscribed
I want to know if this is possible given a delegate variable, to know if it is actually pointing to an object method, and to retrieve this object and the method's name.
e.g:
public delegate void test();
public static test testDel = null;
public void TestMethod()
{
;
}
public void TestDelegate()
{
//here it is not a method of an object
testDel += () => { };
// here it is "TestMethod"
testDel += this.TestMethod;
// i want something like that:
SomeDelegateInfoClass[] infos = testDel.GetAssignedObjectsAndMethodNames();
}
Yes it's possible, delegate contains couple of properties just for that. First one is Target (target object) and second is Method (of type MethodInfo).
var target = testDel.Target; // null for static methods
var methodName = testDel.Method.Name;
Note however that in this case
testDel = () => { };
it's not true that this is "not a method of an object". Compiler will create new type and your empty anonymous function will be a method of that type. So
testDel = () => { };
var targetType = testDel.Target.GetType().Name; // will be something like <>c - name of compiler-generated type
var m = testDel.Method.Name; // will be something like <Main>b__2_0 - compiler generated name
Note also that if you add multiple methods to delegate, like this:
testDel += () => { };
testDel += this.TestMethod;
Target and Method will contain information about last added method. To get information about all of them, you need to use GetInvocationList:
if (testDel != null) {
foreach (var del in testDel.GetInvocationList()) {
Console.WriteLine(del.Target);
Console.WriteLine(del.Method);
}
}
How do I create and call a delegate Action<T> when at runtime I'm receiving the delegate as an object and I know type only at runtime?
For example, In Foo, I define my delegate and want to pass it to a method which receives an Action<int> as an object, along with the data to pass to the delegate. It's contrived I know, but it's to demonstrate my problem.
public void Foo()
{
Action<int> handler = i => Console.WriteLine(i + 1);
Process(handler,4)
}
public void Process(object myDelegate, object data)
{
}
and I'd like to call
myDelegate(data)
All the delegate types (Eg. Action<string>) Are actually types that have an Invoke(...) method.
You should look for that invoke method with reflection and call it, It is relatively slow - So watch out.
This should do it :
Action<string> action = s => Console.WriteLine("Hello " + s);
object obj = action;
// Invoking
obj.GetType ().GetMethod ("Invoke").Invoke (obj, new object[] {"World"});
This works too, I don't know what is faster, you should check it out :
Action<string> action = s => Console.WriteLine("Hello " + s);
Delegate obj = action;
obj.DynamicInvoke(new [] { "World" });
So maybe this then:
public void processAction<T>(Action<T> action, T item) {
action(item);
}
Action<int> customAction = (i) => Console.WriteLine(i);
processAction(customAction, 123);
Action<string> customAction2 = (s) => Console.WriteLine(s);
processAction(customAction2, "Frank Borland");
This should work
Action<int> handler = i => Console.WriteLine(i + 1);
Process(handler, 4);
public void Process(object myDelegate, object data)
{
((Delegate)myDelegate).DynamicInvoke(data);
}
You haven't given a whole lot of context here, but can't you rewrite you Process method as:
public void Process<T>(Action<T> myDelegate, T data)
{
myDelegate(data);
}
I wonder if there is a possibility to make the "dynamic" type for variables work for anonymous delegates.
I've tried the following:
dynamic v = delegate() {
};
But then I got the following error message:
Cannot convert anonymous method to type 'dynamic' because it is not a delegate type
Unfortunately, also the following code doesn't work:
Delegate v = delegate() {
};
object v2 = delegate() {
};
What can I do if I want to make a Method that accepts any type of Delegate, even inline declared ones?
For example:
class X{
public void Y(dynamic d){
}
static void Main(){
Y(delegate(){});
Y(delegate(string x){});
}
}
This works, but it looks a little odd. You can give it any delegate, it will run it and also return a value.
You also need to specify the anonymous method signature at some point in order for the compiler to make any sense of it, hence the need to specify Action<T> or Func<T> or whatever.
Why can't an anonymous method be assigned to var?
static void Main(string[] args)
{
Action d = () => Console.WriteLine("Hi");
Execute(d); // Prints "Hi"
Action<string> d2 = (s) => Console.WriteLine(s);
Execute(d2, "Lo"); // Prints "Lo"
Func<string, string> d3 = (s) =>
{
Console.WriteLine(s);
return "Done";
};
var result = (string)Execute(d3, "Spaghettio"); // Prints "Spaghettio"
Console.WriteLine(result); // Prints "Done"
Console.Read();
}
static object Execute(Delegate d, params object[] args)
{
return d.DynamicInvoke(args);
}
If you declare a type for each of your delegates, it works.
// Declare it somewhere
delegate void DelegateType(string s);
// The cast is required to make the code compile
Test((DelegateType)((string s) => { MessageBox.Show(s); }));
public static void Test(dynamic dynDelegate)
{
dynDelegate("hello");
}
Action _;
dynamic test = (_ = () => Console.WriteLine("Test"));
test() // Test
I'd like to declare an "empty" lambda expression that does, well, nothing.
Is there a way to do something like this without needing the DoNothing() method?
public MyViewModel()
{
SomeMenuCommand = new RelayCommand(
x => DoNothing(),
x => CanSomeMenuCommandExecute());
}
private void DoNothing()
{
}
private bool CanSomeMenuCommandExecute()
{
// this depends on my mood
}
My intent in doing this is only control the enabled/disabled state of my WPF command, but that's an aside. Maybe it's just too early in the morning for me, but I imagine there must be a way to just declare the x => DoNothing() lambda expression in some way like this to accomplish the same thing:
SomeMenuCommand = new RelayCommand(
x => (),
x => CanSomeMenuCommandExecute());
Is there some way to do this? It just seems unnecessary to need a do-nothing method.
Action doNothing = () => { };
I thought I would add some code that I've found useful for this type of situation. I have an Actions static class and a Functions static class with some basic functions in them:
public static class Actions
{
public static void Empty() { }
public static void Empty<T>(T value) { }
public static void Empty<T1, T2>(T1 value1, T2 value2) { }
/* Put as many overloads as you want */
}
public static class Functions
{
public static T Identity<T>(T value) { return value; }
public static T0 Default<T0>() { return default(T0); }
public static T0 Default<T1, T0>(T1 value1) { return default(T0); }
/* Put as many overloads as you want */
/* Some other potential methods */
public static bool IsNull<T>(T entity) where T : class { return entity == null; }
public static bool IsNonNull<T>(T entity) where T : class { return entity != null; }
/* Put as many overloads for True and False as you want */
public static bool True<T>(T entity) { return true; }
public static bool False<T>(T entity) { return false; }
}
I believe this helps improve readability just a tiny bit:
SomeMenuCommand = new RelayCommand(
Actions.Empty,
x => CanSomeMenuCommandExecute());
// Another example:
var lOrderedStrings = GetCollectionOfStrings().OrderBy(Functions.Identity);
This should work:
SomeMenuCommand = new RelayCommand(
x => {},
x => CanSomeMenuCommandExecute());
Assuming you only need a delegate (rather than an expression tree) then this should work:
SomeMenuCommand = new RelayCommand(
x => {},
x => CanSomeMenuCommandExecute());
(That won't work with expression trees as it's got a statement body. See section 4.6 of the C# 3.0 spec for more details.)
I don't fully understand why do you need a DoNothing method.
Can't you just do:
SomeMenuCommand = new RelayCommand(
null,
x => CanSomeMenuCommandExecute());
Action DoNothing = delegate { };
Action DoNothing2 = () => {};
I used to initialize Events to a do nothing action so it was not null and if it was called without subscription it would default to the 'do nothing function' instead of a null-pointer exception.
public event EventHandler<MyHandlerInfo> MyHandlerInfo = delegate { };
Starting with C# 9.0 you can specify discards _ for required parameters. Example:
Action<int, string, DateTime> action = (_, _, _) => { };