I have a problem, Test1 produces "System.ArgumentException : method argument length mismatch" while Test2 and Test3 passes fine. I need to subscribe to an event using reflection, everything works if I use simple methods, but when I get into lambdas, it stops working as expected.
Debugging shows for all lambdas that they are "Void <>m__0(Int32)" which is the correct type for event and the same as "eventInfo.EventHandlerType".
Why does it fail? Or maybe, how to workaround that?
Do c# add more arguments to a method which is created by lambda like in Test1?
::Complete code here:
public class A
{
public void Test1()
{
var str = "aa";
B.Subscribe(typeof(C), "myEvent", (int a) => { var any = str; }, null);
}
public void Test2()
{
B.Subscribe(typeof(C), "myEvent", (int a) => { var any = a; }, null);
}
public void Test3()
{
B.Subscribe<int>(typeof(C), "myEvent", callback, this);
}
public void callback(int a) { }
}
public static class B
{
public static void Subscribe<T>(Type type, string eventName, Action<T> callback, object target)
{
var eventInfo = type.GetEvent(eventName, BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
var handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, target, callback.Method);
eventInfo.AddEventHandler(null, handler);
}
}
public sealed class C
{
public static event Action<int> myEvent;
}
EDIT:
Apparently it's Mono bug. GetInvocationList()[0] to get the Delegate fixes the issue in above example.
But subscribing to event produces "System.InvalidCastException : Cannot cast from source type to destination type." If event is not of type Action but of custom delegate: (if class "C" is like that, it throws, if class "C" is like above, it passes fine)
public sealed class C
{
public static event MyDel myEvent;
public delegate void MyDel(int a);
}
Is it different issue? Edit #2, event expects MyDel type, but gets Action Int32. How can I convert from Action<T> to MyDel or better, to eventInfo.EventHandlerType, because I don't know what type of event there can be.
Actually, after further investigation I noticed that my target was bad.
For methods defined in class, class instance as target is okay.
For lambdas I thought it was null, at least it works with null, as long as it does not interfere with local variables defined inside the method where the lambda was created.
So Action has a property Target, using callback.Target in Delegate.CreateDelegate solves the issue.
The target for lambda actually holds a reference to the class instance and to the all local variables it touches (debugger shows it).
Strange that it worked on newest .NET, maybe a slight difference between mono and .NET.
Related
I am trying to properly check if an object's event has already been set to a specific method.
That stackoverflow question offers 2 solutions :
a quick and dirty one which simply unregisters the method and registers it again.
a more proper one which checks if the delegate to the method has been added.
I have several questions related to the second solution.
Let's assume the following code
public static class Util
{
public static bool IsRegistered<T>(this EventHandler<T> handler, Delegate prospectiveHandler)
=> handler != null
&& handler.GetInvocationList().Any(existingHandler => existingHandler == prospectiveHandler));
}
public class Object1
{
public event EventHandler<string> OnSomething;
public bool CheckOnSomething(Delegate handler) => this.OnSomething.IsRegistered(handler);
}
public class Object2
{
private Object1 o;
public Object2(Object1 o1)
{
this.o = o1;
}
public void CatchSomething(object sender, string something)
{
// ...
}
public void HookToSomething()
{
if (!o.CheckOnSomething( ??? ))
o.OnSomething += this.CatchSomething;
}
}
In order to call CheckOnSomething, i need to pass a delegate to CatchSomething. Do i have to define a new delegate for that, or is there already something i can use ?
If i define a new delegate, will the delegate equality work ? The documentation says it checks for the delegate type, but since i pass the method directly, isn't a new delegate type created on the fly, which would make the equality always return false ?
In order to call CheckOnSomething, I need to pass a delegate to CatchSomething. Do I have to define a new delegate for that, or is there already something I can use ?
You could pass CatchSomething directly:
if (!o.CheckOnSomething(CatchSomething))
o.OnSomething += CatchSomething;
But you would need to update CheckOnSomething to accept a specific delegate type, so that CatchSomething can be converted:
public bool CheckOnSomething(Action<object, string> handler)
=> this.OnSomething.IsRegistered(handler);
This improves type-safety also, because only delegates with the correct signature can now be passed.
If I define a new delegate, will the delegate equality work ? The documentation says it checks for the delegate type, but since I pass the method directly, isn't a new delegate type created on the fly, which would make the equality always return false ?
Passing the method creates a new delegate instance not a new delegate type; the delegate type will always be Action<object, string>.
However, delegate equality relies on target as well as type, so passing CatchSomething will only be considered equal if it is form the same instance.
For example:
var obj1 = new Object1();
var instance1 = new Object2(obj1);
// Creates a delegate instance:
Action<object, string> catchSomething = instance1.CatchSomething;
catchSomething == instance1.CatchSomething; // true
var instance2 = new Object2(obj1);
catchSomething == instance2.CatchSomething; // false
I want to store a method call in an action. That method is a static method, but with a string argument that varies. So I want to store "call StaticMethod with argument "myString" in an Action.
But... without capturing this.
I can store an anonymous method () => StaticMethod(myString) in the action , but this captures the action target (this). (Edit: it doesn't. See the accepted answer).
I can store the static method in the action, but then I'm missing the argument.
I could store the static method and the arguments separately, but due to technical reasons, this is cumbersome and ugly.
Do I have any other possibility?
[Edit]
In other words, I want to do this:
private void MyMethod(string myString){
var action = Call StaticMethod with argument myString.
}
And somewhere else, where I have access to action, but don't know anything about the string, or that there are arguments:
action.Invoke();
action can capture the string, but can't capture this (the call target of MyMethod).
Given the following assumptions:
myString is a local variable, or a parameter to the method (Not! a property or field)
StaticMethod is really a static method
There are no other delegates being constructed in the same method as you want to construct action
then the following:
public void M() {
string myString = "something";
Action action = () => StaticMethod(myString);
}
public static void StaticMethod(string value) { }
will be compiled as this:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public string myString;
internal void <M>b__0()
{
StaticMethod(myString);
}
}
public void M()
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.myString = "something";
Action action = new Action(<>c__DisplayClass0_.<M>b__0);
}
As you can see, your lambda is lifted out to a generated display class, and myString is also lifted out from your method, going from a local variable to a field on that display class. This is the closure, and the object constructed in the M method will be the target of the action, and this closure will not capture this.
You can see this in action here: SharpLab
Note that small changes to your code will invalidate this as the assumptions change. For instance, if you also, in the same method, declare another delegate that also requires a closure and also requires access to this, then the same closure will be shared between the two delegates.
Example:
public void M() {
string myString = "something";
Action action = () => StaticMethod(myString);
Action otherAction = () => StaticMethod(Property);
}
public string Property => "Value";
Generates this code:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public string myString;
public C <>4__this;
internal void <M>b__0()
{
StaticMethod(myString);
}
internal void <M>b__1()
{
StaticMethod(<>4__this.Property);
}
}
public string Property
{
get
{
return "Value";
}
}
public void M()
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.<>4__this = this;
<>c__DisplayClass0_.myString = "something";
Action action = new Action(<>c__DisplayClass0_.<M>b__0);
Action action2 = new Action(<>c__DisplayClass0_.<M>b__1);
}
As you can see, the same closure is used to support both delegates, and now both delegates has a reference to a closure that captures this.
If you can't define your action at call site at compile time e.:
Action a = () => StaticMethod("myString");
Then you will probably want to use expressions for this.
Example Code:
[Fact]
public void SampleActionWithoutThisScopeTests()
{
// Using Compile Time Action
Action compileTimeAction = () => MyStaticMethod("CompileTime myString");
compileTimeAction.Invoke();
// Using Compiled Expression
var myString = "Expression myString";
var methodInfo = this.GetType().GetMethod(nameof(MyStaticMethod), BindingFlags.Static | BindingFlags.Public);
var stringArgumentConstant = Expression.Constant(myString);
var callExpression = Expression.Call(null, methodInfo, stringArgumentConstant);
var lambda = Expression.Lambda<Action>(callExpression);
var action = lambda.Compile();
action.Invoke();
}
public static void MyStaticMethod(string input)
{
Console.WriteLine(input);
}
EDIT
If you can, and meet the requirements for the compiler-generated closure to not contain "this" via normal lambda syntax (see #Lasse V. Karlsen answer, then definitely use that approach!
As you can see in the code below, I have declared an Action<> object as a variable.
Would anybody please let me know why this action method delegate behaves like a static method?
Why does it return true in the following code?
Code:
public static void Main(string[] args)
{
Action<string> actionMethod = s => { Console.WriteLine("My Name is " + s); };
Console.WriteLine(actionMethod.Method.IsStatic);
Console.Read();
}
Output:
This is most likely because there are no closures, for example:
int age = 25;
Action<string> withClosure = s => Console.WriteLine("My name is {0} and I am {1} years old", s, age);
Action<string> withoutClosure = s => Console.WriteLine("My name is {0}", s);
Console.WriteLine(withClosure.Method.IsStatic);
Console.WriteLine(withoutClosure.Method.IsStatic);
This will output false for withClosure and true for withoutClosure.
When you use a lambda expression, the compiler creates a little class to contain your method, this would compile to something like the following (the actual implementation most likely varies slightly):
private class <Main>b__0
{
public int age;
public void withClosure(string s)
{
Console.WriteLine("My name is {0} and I am {1} years old", s, age)
}
}
private static class <Main>b__1
{
public static void withoutClosure(string s)
{
Console.WriteLine("My name is {0}", s)
}
}
public static void Main()
{
var b__0 = new <Main>b__0();
b__0.age = 25;
Action<string> withClosure = b__0.withClosure;
Action<string> withoutClosure = <Main>b__1.withoutClosure;
Console.WriteLine(withClosure.Method.IsStatic);
Console.WriteLine(withoutClosure.Method.IsStatic);
}
You can see the resulting Action<string> instances actually point to methods on these generated classes.
The "action method" is static only as a side effect of the implementation. This is a case of an anonymous method with no captured variables. Since there are no captured variables, the method has no additional lifetime requirements beyond those for local variables in general. If it did reference other local variables, its lifetime extends to the lifetime of those other variables (see sec. L.1.7, Local variables, and sec. N.15.5.1, Captured outer variables, in the C# 5.0 specification).
Note that the C# specification only talks about anonymous methods being converted to "expression trees", not "anonymous classes". While the expression tree could be represented as additional C# classes, for example, in the Microsoft compiler, this implementation is not required (as acknowledged by sec. M.5.3 in the C# 5.0 specification). Therefore, it is undefined whether the anonymous function is static or not. Moreover, section K.6 leaves much open as to the details of expression trees.
Delegate caching behavior was changed in Roslyn. Previously, as stated, any lambda expression which didn't capture variables was compiled into a static method at the call site. Roslyn changed this behavior. Now, any lambda, which captures variables or not, is transformed into a display class:
Given this example:
public class C
{
public void M()
{
var x = 5;
Action<int> action = y => Console.WriteLine(y);
}
}
Native compiler output:
public class C
{
[CompilerGenerated]
private static Action<int> CS$<>9__CachedAnonymousMethodDelegate1;
public void M()
{
if (C.CS$<>9__CachedAnonymousMethodDelegate1 == null)
{
C.CS$<>9__CachedAnonymousMethodDelegate1 = new Action<int>(C.<M>b__0);
}
Action<int> arg_1D_0 = C.CS$<>9__CachedAnonymousMethodDelegate1;
}
[CompilerGenerated]
private static void <M>b__0(int y)
{
Console.WriteLine(y);
}
}
Roslyn:
public class C
{
[CompilerGenerated]
private sealed class <>c__DisplayClass0
{
public static readonly C.<>c__DisplayClass0 CS$<>9__inst;
public static Action<int> CS$<>9__CachedAnonymousMethodDelegate2;
static <>c__DisplayClass0()
{
// Note: this type is marked as 'beforefieldinit'.
C.<>c__DisplayClass0.CS$<>9__inst = new C.<>c__DisplayClass0();
}
internal void <M>b__1(int y)
{
Console.WriteLine(y);
}
}
public void M()
{
Action<int> arg_22_0;
if (arg_22_0 = C.
<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 == null)
{
C.<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 =
new Action<int>(C.<>c__DisplayClass0.CS$<>9__inst.<M>b__1);
}
}
}
Delegate caching behavior changes in Roslyn talks about why this change was made.
As of C# 6, this will always default to instance methods now, and will never be static (so actionMethod.Method.IsStatic will always be false).
See here: Why has a lambda with no capture changed from a static in C# 5 to an instance method in C# 6?
and here: Difference in CSC and Roslyn compiler's static lambda expression evaluation?
The method has no closures and also references a static method itself (Console.WriteLine), so I would expect it to be static. The method will declare an enclosing anonymous type for a closure, but in this instance it is not required.
If I have a class like this:
public class SomeClass
{
public Action<string> SomeAction { get; set; }
public SomeClass()
{
SomeAction = GetSomeAnonymousMethod();
}
private Action<string> GetSomeAnonymousMethod()
{
return (text) =>
{
Console.WriteLine(text);
};
}
}
What happens when I make a new instance of SomeClass? My impression is that the constructor simply calls GetSomeAnonymousMethod(), which returns a new delegate instance (that only contains a reference to the compiler-generated backing method for the anonymous method), and assigns it to the SomeAction property.
Can someone confirm, or is something more sinister happening?
Well, that's nearly all that happens. In this particular case, your lambda expression (it's not an anonymous method, to be picky) doesn't need any state, so the generated method can be static, and a delegate reference can be cached. So the "new delegate instance" part may not be correct.
So it's more like this - at least when compiled with the MS compiler:
public class SomeClass
{
private static Action<string> cachedAction;
public Action<string> SomeAction { get; set; }
public SomeClass()
{
SomeAction = GetSomeAnonymousMethod();
}
private Action<string> GetSomeAnonymousMethod()
{
Action<string> action = cachedAction;
if (action == null)
{
action = AnonymousMethodImplementation;
cachedAction = action;
}
return action;
}
private static void AnonymousMethodImplementation(string text)
{
Console.WriteLine(text);
}
}
You don't need to worry about the details of this - and it's all an implementation detail... just a bit of an optimization. But if you really want to know what's going on, that's closer to reality.
As ever, to see the details of what the compiler's doing, you can always use ildasm (or Reflector in IL mode, for example) and see the generated IL.
Can someone confirm, or is something more sinister happening?
It seems like it's another secret action within the events of new and 2nd Cold War!
Yes, your constructor is doing what you're describing in your question.
I would explain that the anonymous delegate is converted into Action<string> using delegate type inference.
For example, the following code line:
return (text) =>
{
Console.WriteLine(text);
};
...is infered to:
return new Action<string>((text) =>
{
Console.WriteLine(text);
});
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);
}
}