Based on the following question, I found some odd behaviour of the c# compiler.
The following is valid C#:
static void K() {}
static void Main()
{
var k = new Action(new Action(new Action(K))));
}
What I do find strange is the compiler 'deconstructing' the passed delegate.
The ILSpy output is as follows:
new Action(new Action(new Action(null, ldftn(K)), ldftn(Invoke)).Invoke);
As one can see, it automatically decides to use the Invoke method of the delegate. But why?
As it is, the code is unclear. Do we have a triply-wrapped delegate (actual) or is the inner delegate just 'copied' to the outer ones (my initial thought).
Surely if the intent was like the compiler emitted the code, one should have written:
var k = new Action(new Action(new Action(K).Invoke).Invoke);
Similar to the decompiled code.
Can anyone justify the reason for this 'surprising' transformation?
Update:
I can only think of one possible use-case for this; delegate type conversion. Eg:
delegate void Baz();
delegate void Bar();
...
var k = new Baz(new Bar( new Action (K)));
Perhaps the compiler should emit a warning if the same delegate types are used.
The spec (section 7.6.10.5) says:
The new delegate instance is initialized with the same invocation list as the delegate instance given by E.
Now suppose the compiler translated it to something similar to your suggestion of:
new Action( a.Target, a.Method)
That would only ever create a delegate with an invocation list of a single method call. For a multi-cast delegate, it would violate the spec.
Sample code:
using System;
class Program
{
static void Main(string[] args)
{
Action first = () => Console.WriteLine("First");
Action second = () => Console.WriteLine("Second");
Action both = first + second;
Action wrapped1 =
(Action) Delegate.CreateDelegate(typeof(Action),
both.Target, both.Method);
Action wrapped2 = new Action(both);
Console.WriteLine("Calling wrapped1:");
wrapped1();
Console.WriteLine("Calling wrapped2:");
wrapped2();
}
}
Output:
Calling wrapped1:
Second
Calling wrapped2:
First
Second
As you can see, the real behaviour of the compiler matches the spec - your suggested behaviour doesn't.
This is partly due to the somewhat odd "sometimes single-cast, sometimes multi-cast" nature of Delegate, of course...
When you try to treat a delegate as a method, the compiler actually uses the delegate's Invoke() method. So, for example, the two lines below compile to the exact same IL (both call Invoke()):
k();
k.Invoke();
I assume the oddity you're seeing is a consequence of this. The delegate constructor expects a method (or rather, a method group), but it gets a delegate instead. So it treats it as a method and uses the Invoke() method.
As for the meaning, it is delegate that calls delegate that calls the actual method. You can verify this yourself by accessing the delegate's Method and Target properties. In the case of the outer-most delegate, Method is Action.Invoke and Target the inner delegate.
delegate is a class
Action delegate has a constructor like so
public extern Action(object #object, IntPtr method);
Since K is a static method there is no need to pass object to inner most action instance as first argument and hence it passes null
Since second argument is pointer to function therefore it passes pointer of K method using ldftn function
for the remaining Action instances the object is passed is inner Action and the second parameter is the Invoke method since when you call a delegate you're actually calling the Invoke method
Summary
var action = new Action(K) => Action action = new Action(null, ldftn(K))
new Action(action) => new Action(action, ldftn(Action.Invoke))
I hope this explains what is happening?
Related
This question already has answers here:
C# GetDelegateForFunctionPointer with generic delegate
(6 answers)
Closed 2 years ago.
Precondition
The .net method that I will get its pointer is:
public static method
have no overloads
arguments and return value just ValueType (unsafe pointer, primitive type, unmanaged struct)
Reason
Get the method pointer so I can call in C++ program.
This works for me but I need to declare delegate for every method.
I want to get rid of doing things over and over again.
In .net side:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void UpdateDelegate(float delta);
public static void* GetUpdatePointer()
{
var delegateInstance = = new UpdateDelegate(Update);
var pfnUpdate = Marshal.GetFunctionPointerForDelegate(delegateInstance);
return (void*)pfnUpdate;
}
public static Update(float delta)=>{...}
In C++ side:
typedef void (_stdcall * FuncPtr)(float);
void foo()
{
//just pseudo-code showing where is the pfnUpdate from.
FuncPtr pfnUpdate = (FuncPtr)GetUpdatePointer();
pfnUpdate(0.01f);
}
what I want
In c#, I export GetMethodPointer for my native code. It will return a function pointer to specified method, and this pointer can be invoked by native program via stdcall calling convention.
//avoid gc collect this object
static List<Delegate> KeepReference = new List<Delegate>();
public unsafe static void* GetMethodPointer(string name)
{
System.Reflection.MethodInfo methodInfo = typeof(PhysicsMain).GetMethod(name);
// also mark this delegate with [UnmanagedFunctionPointer(CallingConvention.StdCall)] attribute
Type delegateType = ConstructDelegateTypeWithMethodInfo(methodInfo);
var delegateInstance = Delegate.CreateDelegate(delegateType, methodInfo);
KeepReference.Add(delegateInstance);
return (void*)Marshal.GetFunctionPointerForDelegate(delegateInstance);
}
I need ConstructDelegateTypeWithMethodInfo to create a delegate with the same signature as the specified method. And mark [UnmanagedFunctionPointer(CallingConvention.StdCall)] attribute for it so that can be marshaled as a function pointer.
I think it may using IL, Reflection, even Asm to do this. Or using IL to write the whole GetMethodPointer method.
Finally, I got a solution these days. Firstly, I came across Expression.GetDelegateType given by this post. But it did't work for me, because Marshal.GetFunctionPointerForDelegate doesn't support generic delegate type generate by Expression.GetDelegateType. I thought there might be a clue in implementation of Expression.GetDelegateType. So, I browsed referencesource and got a internal method called MakeNewCustomDelegate. This link gives code about how to call the internal method. Things are readily solved!
Edit: I forgot to say, the default unmanaged calling convension of a delegate is stdcall, so we don't need to mark the delegate with [UnmanagedFunctionPointer(CallingConvention.StdCall)] explicitly.
In your example you assume that the class of the method is know function (PhysicsMain).
If UpdateDelegate is also known you can use it easily:
Type delegateType = typeof(UpdateDelegate);
var delegateInstance = Delegate.CreateDelegate(delegateType, methodInfo);
But you can also get this type by name only:
Type delegateType = Type.GetType("Namespace.ClassName+UpdateDelegate");
var delegateInstance = Delegate.CreateDelegate(delegateType, methodInfo);
You can look at delegateType.CustomAttributes and verify that the type has UnmanagedFunctionPointer attribute.
Why can I not use dynamic param in an extension method, as in the following code:
public static class Extension
{
public static void ExtMethod(this Program pg, object asdf) {
new Program();
}
}
public class Program
{
static void Main(string[] args)
{
dynamic d = new ExpandoObject();
d.test = "test";
new Program().ExtMethod(d.test);
Extension.ExtMethod(new Program(), d.test);
}
}
new Program().ExtMethod(d.test); is throwing a compile time error.
But Extension.ExtMethod(new Program(), d.test); is not causing any error.
This is by design, and part of the specification. From the ECMA C# 5 standard, section 12.7.6.3:
In a method invocation (ยง12.6.6.2) of one of the forms [...] if the normal processing of the invocation finds no applicable methods, an attempt is made to process the construct as an extension method invocation. If expr or any of the args has compile-time type dynamic, extension methods will not apply.
The underlying reason for this is that dynamic binding is intended to give the same result as binding at compile-time would... but for extension methods, that would mean retaining all the using directives at execution time. That would be possible, but I suspect it would be very expensive in terms of invocation performance, and the C# design team decided not to go that way.
You need to cast d.test to an object, in other words write;
new Program().ExtMethod((object)d.test);
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);
This question already has answers here:
Delegate Methods vs General Methods
(4 answers)
Closed 9 years ago.
Can anyone say the difference between static/object method call vs delegate method call here the sample provided from my end.
class Program
{
private delegate void TestDeleg1(string input1);
static void Main(string[] args)
{
// Using delege & Lambda expression
TestDeleg1 testDeleg1 = input => { var test = "Hai " + input; Console.WriteLine(test); };
testDeleg1("Microsoft");
// Using simple static method invoke
TestImplementation("Microsoft");
Console.ReadLine();
}
public static void TestImplementation(string input1)
{
var test = "Hai " + input1;
Console.WriteLine(test);
}
}
Because I didn't find any real time usage of delegate method call.
Thanks,
S.Venkatesh
In your example.. there's no difference in their usage. Architecturally however, they are quite different. A delegate is a reference to a method. A static method is.. a method.
Delegates can change what method they reference.. however, a method is just that.. a method.
The usefulness of delegates also comes from the fact that they are types that can be used for example as parameters to methods. For example if you declare
internal delegate bool PredicateOnInt32(int x);
then PredicateOnInt32 is a kind of reference type, and you can use it as a parameter in a method, like
internal int GetFirstNumberWhere(PredicateOnInt32 pred)
{
foreach (int num in this.numbers)
{
if (pred(num))
return num;
}
throw new InvalidOperationException("No number satisfies the specified prediacte");
}
This is just an exemple, of course. But think of LINQ and you understand that it can be useful to have a type that represents a method (or several methods) of a specific signature and return type.
Another use of delegates is in events where a delegate instance is used behind the scene to hold the collection of methods to be invoked when the event "happens". For example when a button is clicked. Different "subscribers" can then add their own methods to the delegate, through the add accessor of the event.
I have a protected method in a base class which accepts a Func<T> and then turns around and executes with some added goodness. Example usage:
public MyResponse DoSomething(MyRequest request)
{
return base.Execute(() => this.Channel.DoSomething(request));
}
What I'm looking to do is take the func delegate instance and redirect the method call in the expression to another instance besides this.Channel, so something like:
protected TResponse Execute<TResponse>(Func<TResponse> command)
{
return command.Method.Invoke(this.otherInstanceOfChannel, command.Target);
}
Here the "this.otherInstanceOfChannel" would be an instance of a different concrete class than the "this.channel" passed in the original call but implements the same interface. I just need to figure out what method is being called and execute that on another instance passing in the original arguments from the caller. I started down the path of MethodCallExpressions and the like but my expression-foo is weak...
Edited/rewrote for clarity - hope this version makes more sense.
Thanks,
Matt
Yes you can do this. No time right now to give you the full solution but here is a skeleton of what you would do:
protected TResponse Execute<TResponse>(Expression<Func<TResponse>> command)
{
// Check that the expression is in the correct format (ie you are calling a method off of a type Channel
// Get the name of the method call. Something like:
var node = expr.Body as MemberExpression;
if (object.ReferenceEquals(null, node))
throw new InvalidOperationException("Expression must be of member access");
var methodName = node.Member.Name;
// Use reflection to invoke methodName on otherInstanceOfChannel
// Cast the results to TResponse and return
}
As you can see the only real trick is the use of Expression<>. The type change is transparent to any client code - they don't have to change at all. Here is some code to get you started with parsing expression trees.
I believe that you can provide the instance in the lambda expression like so:
IMyChannel myChannelInstance = MyChannelInstanceFactory.Create();
Execute(() => myChannelInstance.DoSomething(request))
If this can not be done with lambda expressions and I am sure they can you can change this to a delegate and it would work fine. The lambda expression is pointing to a code execution block and as such you can put whatever matches the expression arguments in that code block.