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.
Related
Is there a way I can pass through an argument to an Action without using an anonymous function?
Eg, the following code works fine:
private void doSomethingAndLogIt(string log, Action dosomething)
{
Debug.WriteLine(log);
dosomething();
}
private void multiplyIt()
{
_result = "great";
}
...
doSomethingAndLogIt("Did something", multiplyIt);
but what I want to do is this:
private void doSomethingAndLogIt(string log, Action<int> dosomething)
{
Debug.WriteLine(log);
dosomething(???);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt(5));
I realise that I can do this:
private void doSomethingAndLogIt(string log, Action<int> dosomething, int inputValue)
{
Debug.WriteLine(log);
dosomething(inputValue);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt, 5);
but it's pretty confusing. I also realise that I can do this:
doSomethingAndLogIt("Did something", () => {
multiplyIt(5);
});
but it would be great if I could do this:
doSomethingAndLogIt("Did something", multiplyIt(5));
You do not need to do anything special. This code below:
doSomethingAndLogIt("Test", () => multiplyIt(5));
will already do what you are after. When the delegate is called, the parameter 5 will be passed in as well. Why? Because the callee will call your delegate, and you will call the method multiply with the argument 5.
Here is a quick test.
It isn't possible to do that as of the current version of C#, here's why...
Let's take your example (fake syntax)
public int MultiplyIt(int value)
{
//Do something that has side-effects
}
public void SomeMethod(Action<int> someAction<int>)
{
//Do something
someAction();
}
Now let's create an override of that method:
public void SomeMethod(int someValue)
{
//Do something
}
Now you call it:
SomeMethod(multiplyIt(5))
Which one does the compiler call?
Lets say you don't overload it (or that for some reason the compiler shouts an error if you do, but it is legal).
What then is the difference between these two calls?
SomeMethod(multiplyIt(5));
SomeMethod(() => multiplyIt(5));
Technically the first one runs multiplyIt before passing its value to SomeMethod. The second one multiplyIt may never be called, or it may alter something and then call it. That is an important distinction. If you add in some method to call it without the () => part, the developer can't know, without reading documentation, how the method call (and the action) are called. Is it a normal method call? The "special" delegate case? Who knows.
The () => isn't that much of a price to pay to be able to read a method and understand that you are passing in a delegate vs a value.
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.
I write this piece of code in one of my C# project:
public static class GetAppendReceiver
{
public static AppendReceiver<DataType> Get<DataType>(AppendReceiver<DataType>.DataProcessor processor0, int delayIn = 0)
{
throw new InvalidOperationException();
}
public static AppendReceiver<string> Get(AppendReceiver<string>.DataProcessor processor0, int delayIn = 0)
{
return new StringAppendReceiver(processor0, delayIn);
}
}
public abstract class AppendReceiver<DataType>
{
public delegate void DataProcessor(DataType data);
...
}
AppendReceiver<DataType> is an Abstract class, DataProcessor is a delegate type.
When calling GetAppendReceiver.Get with a string DataProcessor I expect the overloaded function to be called, but I get the InvalidOperationException.
Here is my call:
class ClassA<DataType>
{
public void RegisterAppendReceiver(AppendReceiver<DataType>.DataProcessor receiver)
{
appendReceivers.Add(GetAppendReceiver.Get(receiver, Delay));
}
}
Example of RegisterAppendReceiver call:
myObject.RegisterAppendReceiver(myMethod);
Where myMethod is defined like this:
public void writeMessage(string strMessageIn)
My question is why I get the wrong overload called, and how can I force the language to call the overload I want ?
Thanks for your help !
Eric Lippert answers this question concisely in his article Generics are not Templates
I don't want to copy the entire article. So the relevant point is this:
We do the overload resolution once and bake in the result.
So the C# compiler decides, at the time it compiles RegisterAppendReceiver, which overload of "GetAppendReceiver.Get" it is going to call. Since, at that point, the only thing it knows about DataType is that DataType can be anything at all, it compiles in the call to the overload that takes an AppendReceiver.DataProcessor, not an AppendReceiver.DataProcessor.
By comparison, the C++ compiler does not behave this way. Each and every time a generic call is made, the compiler does the substitution over again. This is one reason C++ compilers are much slower than C# compilers.
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.
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