I have a class that needs constructed with a void delegate:
//an object that's constructed with a "void delegate of no params"
public class BindableCommand
{
public delegate void ExecuteMethod();
private readonly ExecuteMethod _executeMethod;
public BindableCommand(ExecuteMethod executeMethod)
{
_executeMethod = executeMethod;
}
}
It works when its constructed in the following way:
public class Test
{
public static void Main()
{
//creates a bindable command
BindableCommand b = Create();
}
private static BindableCommand Create(){
BindableCommand b = new BindableCommand(Function);
return b;
}
private static void Function(){}
}
I would now like to pass Function as an argument before constructing BindableCommand.
My attempt fails to compile:
public class Test
{
public static void Main()
{
//creates a bindable command
BindableCommand b = Create(Function);
}
private static BindableCommand Create(Action action){
BindableCommand b = new BindableCommand(action);
return b;
}
private static void Function(){}
}
prog.cs(20,19): warning CS0219: The variable `b' is assigned but its value is never used
prog.cs(24,23): error CS1502: The best overloaded method match for `BindableCommand.BindableCommand(BindableCommand.ExecuteMethod)' has some invalid arguments
prog.cs(9,12): (Location of the symbol related to previous error)
prog.cs(24,43): error CS1503: Argument `#1' cannot convert `System.Action' expression to type `BindableCommand.ExecuteMethod'
But I thought an Action was a void delegate()?
I can't pass a void delegate:
private static BindableCommand Create(delegate void action){/* ... */}
It seems I have to do the following:
private static BindableCommand Create(BindableCommand.ExecuteMethod action){/* ... */}
Is there a way to have the cast occur automatically?
The feature you want C# to have is called "structural delegate conversions". That is, if you have two delegate types and they both take an int and return a string, then you should be able to assign values of one type to another.
C# does not have this feature. Many people, myself included, regret that structural typing was not introduced on delegates in .NET 1.0. Why then was it not included?
The design consideration was that you might want to have semantic information encoded in your delegate types:
delegate R Pure<A, R>(A a);
delegate R Impure<A, R>(A a);
A "pure" function is a function with no side effects, where the outputs are uniquely determined by the inputs. You might want to say, for instance, that a comparison function must be pure. We don't expect a comparison to change its value if the inputs don't change, and we don't expect it to produce a side effect.
Plainly it would be wrong to be able to assign an impure delegate value to a variable of pure delegate type. So the type system prevents it, even if the delegates are structurally identical.
In practice, few people put semantic information like this in delegates. It would have been more convenient to allow structural conversions.
There is one way to do a conversion between structural delegate types but it is not very nice:
Action a = whatever;
ExecuteMethod e = a.Invoke;
That is, the delegate created for e is a delegate to the invoke method of delegate a. So invoking e invokes a, which invokes the desired method. This is an extra step of indirection, but the performance penalty is not too great, one hopes.
But I thought an Action was a void delegate()?
It is. That doesn't mean that there's an implicit conversion between delegate instances with the same signature.
Is there a way to have the cast occur automatically?
No. You could just use Action instead of defining your own delegate in the first place, in which case no conversion will be needed, but if you want to create your own delegate type then you'll need to explicitly convert it to another delegate, regardless of the delegates' signatures.
Related
Suppose that my namespace has 2 delegates:
public delegate void D1(string s);
public delegate void D2(string s);
They are implemented in a static class StClass like this:
public static D1 myD1 { get; set; }
public static D2 myD2 { get; set; }
In each instance of a separate non-static class MyClass I would like to include a delegate that points to one of the 2 static delegates as determined by the constructor. So I would have:
public class MyClass
{
public delegate void D(string s);
public D myD { get; set; }
public MyClass()
{
if()
{
myD = StClass.myD1 //this assignment won't work
}
else
{
myD = StClass.myD2
}
}
I get that I cannot directly link myD to myD1 or myD2 the way it's shown above because from the compiler's standpoint they are instances of different delegate types, but I figure since they all share the same signature there should be a simple way to achieve this. What am I missing?
As per comments, it would probably be better to avoid declaring multiple delegate types with the same signature like this.
However, if you absolutely have to, you can convert them like this:
myD = new D(StClass.myD1);
Note that this uses the value of StClass.myD1 at the time of assignment. If you want to dynamically observe any changes in StClass.myD1, you could use a lambda expression instead:
myD = s => StClass.myD1(s);
This will evaluate the StClass.myD1 property on each invocation.
You start by saying "Suppose that my namespace has 2 delegates:"
public delegate void D1(string s);
public delegate void D2(string s);
But, that's not what you are showing. You are showing the declaration of two, different Delegate Types. You still haven't declared a delegate yet.
Then, within your class, you declare a third delegate type, and an instance of that type:
public delegate void D(string s);
public D myD { get; set; }
Now you start trying to assign delegates of one type to another. That's never going to work; two delegate types, even if their definition completely agrees, remain distinct types. Somewhere, #EricLippert has a blog entry that explains this in detail (but, after a quick search, I can't find it). The pair of types that show this that most C# programmers are familiar with (and curse at) are:
delegate bool Predicate<in T>(T obj);
and
Func<T, bool>
The latter is used for the IEnumerable<T>.Where() extension method, while the former is used in methods like List<T>.FindAll(). Grrrr
The solution, as others have pointed out, is to use a single delegate type. Both the generic Action and Func delegates have been around for nearly forever now. I rarely define delegate types anymore, instead relying on those two types.
I ran into this situation yesterday and it has been gnawing at me. The compiler does not complain about using a reference to a function for my DoThis method when it calls for an Action which to my understanding is a delegate with a 'void' return type.
What is really going on with this Action parameter on the DoThis function?
public class testit
{
// Call DoThis with just a function reference. Should not work, but does.
public void DoThisThing1() {
DoThis(this.thing1);
}
// Call DoThis with an action. This is correct.
public void DoThisThing2() {
DoThis(new Action<string, string>(this.thing2));
}
private void DoThis(Action<string, string> thing)
{
// Do some common things here.
// Invoke Action
thing.Invoke("1", "2");
// Do other things.
}
private void thing1(string p1, string p2){}
private void thing2(string p1, string p2){}
}
If your question is why this works:
DoThis(this.thing1);
Then that is implicitly:
DoThis(new Action<string,string>(this.thing1));
(where the delegate type is inferred from the resolved method signature of DoThis)
Simply: the compiler fills in some things for us - syntactic sugar that has existed since C# 2. In C# 1.1, it wouldn't have compiled.
I'm slowly getting my head around delegates, in that the signature of the delegate must match that of the method it is delegating too.
However, please review the following code.
public static void Save()
{
ThreadStart threadStart = delegate
{
SaveToDatabase();
};
new Thread(threadStart).Start();
}
private static void SaveToDatabase() { }
I am now stumped at this point, because the delegate returns void (as that is what SaveToDatabase() is) but, it's clearly returning a ThreadStart... Or is it?
If I were to write my own delegate, I would have no idea how to achieve this because the delegate would have to be void to match the return type of SaveToDatabase(). But it can't be; it would be of type ThreadStart!
My question is, have I totally mis-understood or is this made possible by some .NET trickery? If I wanted to write this method but create my own delegate, how would I ?
The word "delegate" is a bit abused. It's easier with classes and objects. A "class" is like a blueprint for an object. An "object" is an actual instance in memory, which follows the blueprint of the class.
For delegates we use the same word, hence I suspect your confusion. Consider the following code:
class Main
{
public delegate int DelegateType(string x);
public int SomeFunction(string y) { return int.Parse(y)*2; }
public void Main()
{
DelegateType delegateInstance = null;
delegateInstance = SomeFunction;
int z = delegateInstance("21");
Console.WriteLine(z);
}
}
This code outputs "42".
The DelegateType is the type of the delegate. Like a class is a blueprint for an object, the delegate is a blueprint for a function.
So later we create a variable named delegateInstance which is of the type DelegateType. To that variable, we can assign ANY function that takes a single string parameter and returns an integer. Note, that we assigned the function itself, not the results of that function. It's like the delegateInstance variable is now a synonym of that function. Indeed, as demonstrated a line later, we can now use delegateInstance to call that funcion! Just as if delegateInstance was a function itself. But, since it is variable, we can also do all the same things that we usually do with variables - like pass them as parameters to other functions, or even return from other functions (A function that returns a function! Wrap your head around that!)
OK, let's see the code that baffled you.
public static void Save()
{
ThreadStart threadStart = delegate
{
SaveToDatabase();
};
new Thread(threadStart).Start();
}
private static void SaveToDatabase() { }
First thing to notice is that you used an anonymous delegate. Another misuse of the term. When compiled, it results in something like this:
public static void Save()
{
ThreadStart threadStart;
threadStart = __ASDASDASD6546549871;
var tmp = new Thread(threadStart);
tmp.Start();
}
private static void SaveToDatabase() { }
private void __ASDASDASD6546549871()
{
SaveToDatabase();
}
Note that your anonymous function was actually transformed to a completely regular function with a random name, and then that function was assigned to the threadStart variable.
So now this is just like the example above. Just replace DelegateType with ThreadStart, delegateInstance with threadStart and SomeFunction with __ASDASDASD6546549871.
Does it make sense now?
I am now stumped at this point, because the delegate returns void (as that is what SaveToDatabase() is) but, it's clearly returning a ThreadStart... Or is it?
If I were to right my own delegate, I would have no idea how to achieve this because the delegate would have to be void to match the return type of SaveToDatabase(), but can't be because it would be of type ThreadStart!
ThreadStart is defined as a delegate. In fact, it is defined as
public delegate void ThreadStart();
So your code is not returning a delegate or a ThreadStart. It is simply defining a function that matches the ThreadStart delegate definition. The Thread constructor expects a ThreadStart delegate, which you have defined as the variable threadStart, which points to the SaveToDatabase function.
I tend to think of delegates as the old C++ term "function pointers". Delegates allow us to specify what kind of function (parameters and return type) should be passed as a parameter to another function.
My question is, have I totally mis-understood or is this made possible by some .NET trickery? If I wanted to write this method but create my own delegate, how would I ?
I think you may have misunderstood. But to answer this question specifically, the method you would write would just need to match the definition specified by the delegate type, in this case ThreadStart. That method definition must return void and accept no parameters. Your SaveToDatabase method matches this delegate type and is therefore the proper delegate method to create.
When you are going to run an administrated subProcess, the method that is going to be executed gets represented by ThreadStart or ParameterizedThreadStart, but SaveToDatabase is void and it will be executed with void signature, not with ThreadStart type.
Example from MSDN:
class Test
{
static void Main()
{
// To start a thread using a static thread procedure, use the
// class name and method name when you create the ThreadStart
// delegate. Beginning in version 2.0 of the .NET Framework,
// it is not necessary to create a delegate explicityly.
// Specify the name of the method in the Thread constructor,
// and the compiler selects the correct delegate. For example:
//
// Thread newThread = new Thread(Work.DoWork);
//
ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
Thread newThread = new Thread(threadDelegate);
newThread.Start();
// To start a thread using an instance method for the thread
// procedure, use the instance variable and method name when
// you create the ThreadStart delegate. Beginning in version
// 2.0 of the .NET Framework, the explicit delegate is not
// required.
//
Work w = new Work();
w.Data = 42;
threadDelegate = new ThreadStart(w.DoMoreWork);
newThread = new Thread(threadDelegate);
newThread.Start();
}
}
class Work
{
public static void DoWork()
{
Console.WriteLine("Static thread procedure.");
}
public int Data;
public void DoMoreWork()
{
Console.WriteLine("Instance thread procedure. Data={0}", Data);
}
}
From MSDN
A delegate is a type that references a method. Once a delegate is assigned a method, it behaves exactly like that method. The delegate method can be used like any other method, with parameters and a return value, as in this example:
public delegate int PerformCalculation(int x, int y);
So return type of the delegate will match the return type of the method it is delegating.
Any method that matches the delegate's signature, which consists of the return type and parameters, can be assigned to the delegate. This makes is possible to programmatically change method calls, and also plug new code into existing classes. As long as you know the delegate's signature, you can assign your own delegated method.
Say I have 2 classes, class A and class B. Class A creates an instance of Class B. Class A has a function that I would like to pass into a method from Class B.
class A {
void Main(string[] args) {
B classB=new B();
DelegateCaller(new delFunction(classB.TheFunction()); // <-- Won't compile (method name expected)
DelegateCaller(new delFunction(B.TheFunction()); // <-- Won't compile (object reference is req'd)
}
public delegate string delFunction();
public DelegateCaller(delFunction func) {
System.Console.WriteLine(func());
}
}
class B {
public string TheFunction() {
return "I'm Printing!!!";
}
}
I'm not sure if it a syntax issue or it's just something I can't do. Maybe I need to define the delegate in B, but reference it in A? What about B's this pointer?
It's just a syntax issue; get rid of the parentheses after classB.TheFunction - they indicate that you wish to invoke the method.
DelegateCaller(new delFunction(classB.TheFunction));
Do note that there is an implicit conversion available from a method-group, so you can just do:
DelegateCaller(classB.TheFunction);
Also note that creating your own delegate-type in this case is unnecessary; you could just use the in-built Func<string> type.
EDIT: As Darin Dimitrov points out, there is also the unrelated issue of calling an instance method as though it were a static method.
Try like this:
class A
{
static void Main()
{
B classB = new B();
DelegateCaller(classB.TheFunction);
}
public delegate string delFunction();
public static void DelegateCaller(delFunction func)
{
Console.WriteLine(func());
}
}
class B
{
public string TheFunction()
{
return "I'm Printing!!!";
}
}
Let me elaborate about the different changes I've made to your initial code:
TheFunction in class B needs to be public so that you can access it from class A
The DelegateCaller method in class A should be static and not necessarily return a value (declare it as void) if you want to call it from the static Main method.
The definition of the delFunction delegate should return a string.
Take the parenthesis off the end of TheFunction. You want the method, not the result of a call to the method.
If you want to capture an instance method for usage in a general purpose fashion you should use Delegate.CreateDelegate(Type,MethodInfo). This is nice as it allows you to create an "open delegate" meaning it isn't bound to an instance and can take any instance that is a ClassB. It makes reflection quite fast if you know the type information, as this method will perform much faster than the equivalent statement using MethodInfo.Invoke.
DelegateCaller(new delFunction(B.TheFunction());
Should be
DelegateCaller(new delFunction(B.TheFunction);
To use classB.TheFunction you would need to make TheFunction static. You pass in the function with no parens.
A delegate is a function pointer. So it points to a function which meets the criteria (parameters and return type).
This begs the question (for me, anyway), what function will the delegate point to if there is more than one method with exactly the same return type and parameter types? Is the function which appears first in the class?
Thanks
The exact method is specified when you create the Delegate.
public delegate void MyDelegate();
private void Delegate_Handler() { }
void Init() {
MyDelegate x = new MyDelegate(this.Delegate_Handler);
}
As Henk says, the method is specified when you create the delegate. Now, it's possible for more than one method to meet the requirements, for two reasons:
Delegates are variant, e.g. you can use a method with an Object parameter to create an Action<string>
You can overload methods by making them generic, e.g.
static void Foo() {}
static void Foo<T>(){}
static void Foo<T1, T2>(){}
The rules get quite complicated, but they're laid down in section 6.6 of the C# 3.0 spec. Note that inheritance makes things tricky too.
So it points to a function which meets the criteria (parameters and return type).
Nope.
To add some background to Henk's Answer:
Just like int x is an variable which can contain integers, A delegate is a variable which can contain functions.
It points to whatever function you tell it to point to.
EG:
// declare the type of the function that we want to point to
public delegate void CallbackHandler(string); //
...
// declare the actual function
public void ActualCallbackFunction(string s){ ... }
...
// create the 'pointer' and assign it
CallbackHandler functionPointer = ActualCallbackFunction;
// the functionPointer variable is now pointing to ActualCallbackFunction