Invocation of Delegates Issue - c#

Like I told you in my previous question I am learning about delegates or better said I am trying to answer all my question I have about those bad boys.
MSDN Docs somehow do not really help me much. They couldn't really answer me following issue:
I have this code:
public delegate void Del(string message);
Now what you told me yesterday is that somehow compiler creates a delegate from that line with the type Del.
You also told me yesterday that every delegate inherits from Delegate (with cap letter) class.
So far so good but now my question is I can do following Del d = DoSomething; d(); but why can't I do the same with Delegate?.
I cannot do something like this Delegate e = d; e(). There is only DynamicInvoke method but no direct invocation.
What is that Delegate (with cap letter) good for anyway if everybody suggests somehow to stay away from it?
I wish you guys not to link me to some other already existing answer. I would appreciate if somebody could take 5 min time to discuss with me here about this if possible. Thanks

Each delegate has a strong signature: both return types and argument types are required to be specified. The base Delegate class is here to materialize any delegate, but not with purpose to be called directly.
It's the same as the Enum class. It's a base class to help dealing with enums.

I think it might be because when you declare a delegate Del the compiler creates a class Del that sub-classes Delegate which is an abstract class. So
Del d = DoSomething;
is actually a shortcut for
Del d = new Del(DoSomething);
you can't do the same with Delegate because it is an abstract class, so
Delegate e = new Delegate(d);
is illegal.

Note that, per your code the snippet
Del d = DoSomething;
d();
will fail to compile, with a invalid signature error, as the call does not match the signature (you will need something like d("Hello world") to make it work. Also using a return value of d will yield a compile time error (e.g. var result = d("");), because the compiler knows that Del delegates have a void return.
When using the same thing via a Delegate instance, all that can be known about the value is that is invokable, and the return type and the parameters (in number or in type) are unknown. The system enables you to invoke the delegate indirectly, via DynamicInvoke, dynamic here meaning that any resolution and any errors will not be known until execution time.

Related

How to possibly extend a generic delegate type with a non-generic one in C#?

I would like to define a non-generic delegate extending a generic delegate to define a default for the generic delegate type parameter, i.e. something like this (not a valid piece of C# code but an obvious-to-understand illustration for the concept I mean hopefully):
public delegate void MyDelegate<T>(T arg);
public delegate void MyDelegate(object arg) : MyDelegate<object>;
What is, if any, the correct way to declare this?
Needless to say I can just declare 2 independent delegates to achieve virtually same effect a way like this:
public delegate void MyDelegate<T>(T arg);
public delegate void MyDelegate(object arg);
but I'd like to do to make the actual relation between them (the fact a bare MyDelegate type is meant to equal MyDelegate<object>, the way like a class extending another class or literally) definite and make the following code will become valid if possible:
MyDelegate<object> d1;
MyDelegate d2;
MyDelegate d1 = d2;
Sorry, I may have been too harsh in saying you should know delegate types are sealed. It is clear in the specification, but I took a look at the latest version of the MSDN language documentation, and it does not seem to mention this at all. Well, anyway…they are sealed. 😊 You can't create a new class that inherits a delegate type, and you certainly can't use the delegate keyword to declare a new delegate type that inherits another delegate type (the keyword has a very specific syntax, and doesn't even allow an inheritance syntax).
It's still not really clear to me what you're trying to do. But, in some sense, a delegate type is an interface with just one member. It's more flexible, of course, because the implementation isn't in a single type, but can be any method from any type. But conceptually, the two are very similar.
In that sense, you could express your intent in code using an interface instead of a delegate. For example:
interface IDelegate<T>
{
void M(T arg);
}
interface IDelegateObject : IDelegate<object> { }
Of course, the problem with this is that now you need some type that will implement the interface in question. Any given type will only be able to implement any given interface once, so you lose a lot of the flexibility that delegate types would ordinarily give you.
But, you can do something like this:
IDelegate<object> d1;
IDelegateObject d2;
d1 = d2;
That is, since IDelegateObject inherits IDelegate<object>, and thus "is a" IDelegate<object>, you can then assign a value of type IDelegateObject, i.e. d2, to a variable of type IDelegate<object>, i.e. d1.

Subscribe to a delegate that was passed as method argument

I'm attempting to build a recurring programming pattern into a generic class for code re-use. Part of this pattern thread-safely subscribes/unsubscribes to a delegate as needed during asynchronous operations (multicast delegate used as event).
The following code does not compile. The problem I'm facing is that C# allows me to pass a delegate as method argument, but anywhere inside MyWorker class the subscribe +=,-= operations cause errors. (Works fine on the same delegate from outside).
[Operator '+=' cannot be applied to operands of type 'delegateT' and 'method group']
Syntactical errors?
delegate scope limitation?
is this disallowed by the language?
public class MyWorker<delegateT,argT>
{
private delegateT mDelegate;
public MyWorker(delegateT d)
{
mDelegate = d; //save delegate (reference?) for use later
}
public void DoWorkAsync()
{
mDelegate += m_subscriber; //ERROR: Operator '+=' cannot be applied to operands of type 'delegateT'...
//...Do some work that causes delegate to fire...
mDelegate -= m_subscriber; //ERROR: Operator '-=' cannot be applied to operands of type 'delegateT'...
}
private void m_subscriber(argT arg)
{
Console.WriteLine("Received: " + arg.ToString());
}
}
Note that generics do not seem to be the cause; I've tried using static types instead with the same result. I've also tried passing delegate with the 'ref' keyword to make sure i'm storing and referencing the original object rather than a local copy...maybe a secondary issue, but one step at a time.
[UPDATE]
OIC, inability to constrain Delegate type seems to be a major issue here, and prevents generic usage the way I'm doing it. Thanks for pointing that out Ron.
To clarify the original intent:
I use delegates for internal events; more flexibility than strict 'event' type. I'm searching for some way to pass a delegate (ref?) to MyWorker class at runtime. Then MyWorker performs some background tasks which subscribe and unsubscribe as necessary to receive events during operation, before finally exiting for garbage collection. I do this for 30+ nearly identical tasks/events, which is why creating a reusable (generic?) class is highly desirable.
Delegates in my system have a strict form such as:
delegate void delegateEvent1(Class1 arg);
delegate void delegateEvent2(Class2 arg);
...
delegate void delegateEventN(ClassN arg);
Plan B is to pass Action delegates to subscribe and unsubscribe from within MyWorker. This is quite a bit messier as it requires 2 Actions<> to be created for each invocation rather than just cleanly passing the desired delegate.
Open to any suggestions...
It's not because you named your generic parameter delegateT compiler knows it's some delegate type and so it can't know that some += operator exists on that type.
It would need some generic constraint to enforce this ; but AFAIK that's not possible in C#
As KiwiPiet pointed in comment you can maybe try to add a constraint for some delegate type though
As pointed by Ron Beyer in comment it's also not possible to constraint to some delegate type too

Disambiguating between overloaded methods passed as delegates in an overloaded call

Suppose I had this in C#:
class OverloadTest
{
void Main()
{
CallWithDelegate(SomeOverloadedMethod);
}
delegate void SomeDelegateWithoutParameters();
delegate void SomeDelegateWithParameter(int n);
void CallWithDelegate(SomeDelegateWithoutParameters del) { }
void CallWithDelegate(SomeDelegateWithParameter del) { }
void SomeOverloadedMethod() { }
void SomeOverloadedMethod(int n) { }
}
Of course, this does not compile, because the line CallWithDelegate(SomeOverloadedMethod); is ambiguous.
Now, suppose there was only one CallWithDelegate(SomeDelegateWithoutParameter del) function (no overloads). In this case, there would be no ambiguity, because, from what seems to be happening, the compiler can look at the parameter type and discard SomeOverloadedMethod(int n) from the candidate list (since it can only take a SomeDelegateWithoutParameters), and so it compiles.
I don't intend to write code like this; this is just out of curiosity, from a compiler writer point-of-view. I couldn't find an answer about this, since it is quite confusing to put into words.
I'd like to know if there is any way in C# to disambiguate that call in Main() in the example given, so that it would compile. How can you specify it so that it resolves into CallWithDelegate(SomeDelegateWithoutParameters del) being passed SomeOverloadedMethod(), or CallWithDelegate(SomeDelegateWithParameter del) being passed SomeOverloadedMethod(int n)?
There are several ways to disambiguate overload resolution of method groups.
Method 1: cast the method group
CallWithDelegate((SomeDelegateWithoutParameters)SomeOverloadedMethod);
CallWithDelegate((SomeDelegateWithParameter)SomeOverloadedMethod);
This disambiguates the overload. That's pretty uncommon syntax in the wild, but it works (C# 5 spec §6.6 Method group conversions):
As with all other implicit and explicit conversions, the cast operator can be used to explicitly perform a method group conversion.
[...]
Method groups may influence overload resolution, and participate in type inference.
Method 2: instantiate the delegate explicitly
CallWithDelegate(new SomeDelegateWithoutParameters(SomeOverloadedMethod));
CallWithDelegate(new SomeDelegateWithParameter(SomeOverloadedMethod));
This is the same as the previous method without the syntactic sugar. See the spec at §7.6.10.5 Delegate creation expressions for more details.
The binding-time processing of a delegate-creation-expression of the form new D(E), where D is a delegate-type and E is an expression, consists of the following steps:
If E is a method group, the delegate creation expression is processed in the same way as a method group conversion (§6.6) from E to D.
[...]
There's even an example closely related to your question:
As described above, when a delegate is created from a method group, the formal parameter list and return type of the delegate determine which of the overloaded methods to select. In the example
delegate double DoubleFunc(double x);
class A
{
DoubleFunc f = new DoubleFunc(Square);
static float Square(float x) {
return x * x;
}
static double Square(double x) {
return x * x;
}
}
the A.f field is initialized with a delegate that refers to the second Square method because that method exactly matches the formal parameter list and return type of DoubleFunc. Had the second Square method not been present, a compile-time error would have occurred.
Method 3: use a lambda
CallWithDelegate(() => SomeOverloadedMethod());
CallWithDelegate(i => SomeOverloadedMethod(i));
CallWithDelegate((int i) => SomeOverloadedMethod(i)); // Explicit types, if needed
This form is not ambiguous but it has an indirection (the lambda is called, and it then calls the target method). This may get optimized by the JIT though, and it most probably won't have a visible performance impact anyway.
Method 4: use anonymous delegates
CallWithDelegate(delegate() { SomeOverloadedMethod(); });
CallWithDelegate(delegate(int i) { SomeOverloadedMethod(i); });
This is equivalent to the lambda calls, but it uses the bulkier (and older) delegate syntax.
If you'd like to know the exact overload resolution rules, they're described in the spec in §7.5.3 Overload resolution.
While i am no compiler expert, I can tell you that since you have supplied 2 overloaded methods that match both methods the compiler has no way of identifying your actual intention. It can't compile because at compile time there is currently no actual identifying information as now mentioned by Lucas you can cast to remove the ambiguity. For the compiler to solve this it would need run-time information of which method you actually wanted to use based on arguments that you may try and pass in.

contravariance seem to cause a conflicted behavior

The following example is taken from C# in Depth: What you need to master C# 2 and 3, and seems to only only cause a breaking change as jskeet has identified, but be wrong. Please explain:
delegate void SampleDelegate(string x);
public void CandidateAction (string x)
{
Console.WriteLine("Snippet.CandidateAction")
}
public class Derived: Snippet
{
public void CandidateAction (object x)
{
Console.WriteLine("Derived.CandidateAction")
}
}
....
Derived x = new Derived();
SampleDelegate factory = new SampleDelegate (x.CandidateAction);
factory ("test");
Now, why should it work altogether as SampleDelegate accept string not the object. And to my knowledge, object doesn't derive from the string. It is the other way around. That's what contravariance permits under c# 2.0. The seems to demonstrate the opposite effect.
Conceptually, Derived.CandidateAction's signature is saying, "I can handle any object you want to throw at me." SampleDelegate's contract is "You have to be able to handle a string." Now if a method can handle any object, it can certainly handle a string. So Derived.CandidateAction is capable of fulfilling what SampleDelegate needs, and can therefore be assigned to a SampleDelegate variable.
I wrote a more detailed discussion of this (admittedly from a C# 4 point of view) at http://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.html.
Contravariance allows you to use a method which has parameters which are a base type of the parameters in the delegate method signature.
The delegate signature defines what types will be passed to the method. The method itself can have types that are less "specific". In your example, when the delegate is invoked as string is being passed. It is perfectly ok for the actual method to only want an object because a variable of type object is allowed to hold an instance of type string.
This is most useful in event handling scenarios where you can write an event handler like this that can be attached to almost any event (even when the args parameter being passed is more specific like ItemCheckedEventArgs):
public void GenericHandler(object source, EventArgs args) {
//do something generic
}

Convert this delegate to an anonymous method or lambda

I am new to all the anonymous features and need some help. I have gotten the following to work:
public void FakeSaveWithMessage(Transaction t)
{
t.Message = "I drink goats blood";
}
public delegate void FakeSave(Transaction t);
public void SampleTestFunction()
{
Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(FakeSaveWithMessage));
}
But this is totally ugly and I would like to have the inside of the Do to be an anonymous method or even a lambda if it is possible. I tried:
Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; });
and
Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; });
but these give me
Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type** compile errors.
What am I doing wrong?
Because of what Mark Ingram posted, seems like the best answer, though nobody's explicitly said it, is to do this:
public delegate void FakeSave(Transaction t);
Expect.Call(delegate { _dao.Save(t); }).Do( new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; }));
That's a well known error message. Check the link below for a more detailed discussion.
http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/
Basically you just need to put a cast in front of your anonymous delegate (your lambda expression).
In case the link ever goes down, here is a copy of the post:
They are Anonymous Methods, not
Anonymous Delegates.
Posted on December 22, 2007 by staceyw1
It is not just a talking point because
we want to be difficult. It helps us
reason about what exactly is going on.
To be clear, there is *no such thing
as an anonymous delegate. They don’t
exist (not yet). They are "Anonymous
Methods" – period. It matters in how
we think of them and how we talk about
them. Lets take a look at the
anonymous method statement "delegate()
{…}". This is actually two different
operations and when we think of it
this way, we will never be confused
again. The first thing the compiler
does is create the anonymous method
under the covers using the inferred
delegate signature as the method
signature. It is not correct to say
the method is "unnamed" because it
does have a name and the compiler
assigns it. It is just hidden from
normal view. The next thing it does
is create a delegate object of the
required type to wrap the method. This
is called delegate inference and can
be the source of this confusion. For
this to work, the compiler must be
able to figure out (i.e. infer) what
delegate type it will create. It has
to be a known concrete type. Let
write some code to see why.
private void MyMethod()
{
}
Does not compile:
1) Delegate d = delegate() { }; // Cannot convert anonymous method to type ‘System.Delegate’ because it is not a delegate type
2) Delegate d2 = MyMethod; // Cannot convert method group ‘MyMethod’ to non-delegate type ‘System.Delegate’
3) Delegate d3 = (WaitCallback)MyMethod; // No overload for ‘MyMethod’ matches delegate ‘System.Threading.WaitCallback’
Line 1 does not compile because the
compiler can not infer any delegate
type. It can plainly see the signature
we desire, but there is no concrete
delegate type the compiler can see.
It could create an anonymous type of
type delegate for us, but it does not
work like that. Line 2 does not
compile for a similar reason. Even
though the compiler knows the method
signature, we are not giving it a
delegate type and it is not just going
to pick one that would happen to work
(not what side effects that could
have). Line 3 does not work because
we purposely mismatched the method
signature with a delegate having a
different signature (as WaitCallback
takes and object).
Compiles:
4) Delegate d4 = (MethodInvoker)MyMethod; // Works because we cast to a delegate type of the same signature.
5) Delegate d5 = (Action)delegate { }; // Works for same reason as d4.
6) Action d6 = MyMethod; // Delegate inference at work here. New Action delegate is created and assigned.
In contrast, these work. Line 1 works
because we tell the compiler what
delegate type to use and they match,
so it works. Line 5 works for the
same reason. Note we used the special
form of "delegate" without the parens.
The compiler infers the method
signature from the cast and creates
the anonymous method with the same
signature as the inferred delegate
type. Line 6 works because the
MyMethod() and Action use same
signature.
I hope this helps.
Also see:
http://msdn.microsoft.com/msdnmag/issues/04/05/C20/
What Mark said.
The problem is that Do takes a Delegate parameter. The compiler can't convert the anonymous methods to Delegate, only a "delegate type" i.e. a concrete type derived from Delegate.
If that Do function had took Action<>, Action<,> ... etc. overloads, you wouldn't need the cast.
The problem is not with your delegate definition, it's that the parameter of the Do() method is of type System.Delegate, and the compiler generated delegate type (FakeSave) does not implicitly convert to System.Delegate.
Try adding a cast in front of your anonymous delegate:
Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; });
Try something like:
Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; }));
Note the added EventHandler around the delegate.
EDIT: might not work since the function signatures of EventHandler and the delegate are not the same... The solution you added to the bottom of your question may be the only way.
Alternately, you could create a generic delegate type:
public delegate void UnitTestingDelegate<T>(T thing);
So that the delegate is not Transaction specific.

Categories