Referencing a delegate via another delegate in C# - c#

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.

Related

Restrict Return Type of Generic Delegate Irrespective of Parameters

I'm trying to restrict the return type of a generic delegate without specifying the parameter signature, and I don't know how to do this, or if it is even possible.
How can I do this or is it impossible?
My research has come up dry. Some pseudo-C# code would probably help steer you toward what I'm trying to do:
public class SomeClass< T, U > where T : Delegate // returning U
{
private someDelegate;
public SomeClass( T someDelegate )
{
this.someDelegate = someDelegate;
}
public U Run()
{
return someDelegate.DynamicInvoke();
}
}
... Elsewhere
public delegate string aDelegate();
public static string SayHi()
{
return "Hello!";
}
aDelegate greeter = SayHi;
var something = new SomeClass< aDelegate, string>( greeter );
Console.WriteLine( something.Run() ); // Should write "Hello" to the console.
I know this is a rather contrived pseudo example. I aim for a more involved usage, of course. I'm trying to write a console menu class that would associate a list of given menu options with actions that would fire depending on what option the user chooses. Right now, it just returns the string the user chose from the menu. What I'd like be able to do is return what--if anything--the associated method returns. This could perhaps be returned with the user chosen option string in a tuple... But, I figured this mini-example just cut straight to the technical hurdle I'm experiencing.
Thanks!
.NET already defines a generic delegate that returns the generic argument as it's result, Func<T>. You don't even need to define it.
public class SomeClass<U>
{
private Func<U>;
public SomeClass(Func<U> someDelegate)
{
this.someDelegate = someDelegate;
}
public U Run()
{
return someDelegate();
}
}
There's no real useful reason to allow a user of the type to provide any arbitrary delegate of the same signature. Really I'd advise you to avoid using any delegates in your code other than Func and Action (with various different numbers of generic arguments) whenever possible, as it's just creating a hassle to do so. I would consider it a reasonable restriction on any caller that has a delegate of a different type but the same signature to simply convert it to a Func<T> anyway, it's not like it's even a difficult conversion for them.
If you don't want to use Func<T> (as Servy suggests), e.g. if you have a custom delegate of your own that you want to be passed with type-safety, then perhaps you can make your custom delegate generic with respect to its return type. Then you can do it this way:
public delegate T MyDelegate<T>();
public class Foo<T>
{
private readonly MyDelegate<T> _delegate;
public Foo(MyDelegate<T> handler)
{
_delegate = handler;
}
public T Bar()
{
return _delegate();
}
}

C# declare delegate signature from existing function

I would like to avoid declaring the function signature twice for a delegate when I already have the function sitting there in the code. I feel like I'm missing something obvious but I can't seem to find how to do this by googling.
public class SomeLibraryV1
{
public int DoSomething(int x, int y);
}
public class SomeLibraryV2
{
public int DoSomething(int x, int y);
}
public class SomeConsumer
{
// Create the delegate by manually declaring the signature again :-(
private delegate int DoSthDelegate(int x, int y);
public void Run(DoSthDelegate aDelegate)
{
aDelegate(1, 2);
}
}
So what I'd like to do is just avoid the second declaration of int fn(int, int). Something like
public class SomeConsumer
{
// Create the delegate from the function signature we already know :-)
public delegate DoSthDelegate(SomeLibrary.DoSomething);
public void Run(DoSthDelegate aDelegate)
{
aDelegate(1, 2);
}
}
This would not only save me typing every single declaration twice but would save me having to maintain things in two places should the signature of DoSomething change.
You´re missing an assential - not to say the important point - on delegates. You can register any method with the same signature. Thus it´s not really helpful to bind your delegate to just one fix method. If you´re only invoking the same method, than you shouldn´t use a delegate at all. Simply call your DoSomething-method directly in your Run-method instead of invoking the delegate:
Run()
{
var retVal = DoSomething(3, 5)
}
In fact a delegate is nothing but a signature which may be satisified by multiple methods as well. Moreover that´s the basis for events where you can register multiple event-handlers via the same delegate-definition.
So all a delegate does it to indicate that there is a method that expects two int-values and returns an int. However it doesn´t make any assumption on where this method is defined - it might also be an anonymous one, e.g.:
Run((x, y) => x + y);
Of course this is some duplicated typing. However it ensures that you can´t invoke a method that doesn´t fit the delegates signature. So the only thing you can do is to use the Func-delegate instead of creating your own one:
public TheFunc Func<int, int, int> { get; set; }
You can set this via this statement:
Run(instanceOfMyLibrary.DoSomething);
or also:
Func<int, int, int> f = instanceOfyLibrary.DoSomething;
Run(f);
NB: Your delegate must be public in order to provide it as parameter to your Run-method.

Can an Action be assigned to a void delegate implicitly?

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.

Delegates with same signature

My question is a bit similar to this one: How to convert an action to a defined delegate of the same signature?
Why there is no implicit convertion between delegates with same signature. For example, code:
class Program
{
private delegate void Foo1(int x);
private delegate void Foo2(int x);
static void Main(string[] args)
{
Foo1 foo1 = Console.WriteLine;
Foo2 foo2 = Console.WriteLine;
Call(foo1);
Call2(foo2);
}
static void Call(Action<int> action)
{
action(10);
}
static void Call2(Foo1 action)
{
action(10);
}
}
it does not compile because there isn't implicit convertion from Action<int> to Foo1.
But normaly it's the same thing. So it mean this names are aliases, not actualy names. So i think it was great idea to think about it like aliases. So in this case we have 3 aliases of a delegate, that get one int value and returns nothing. And this delegates are fully interchangeable one by another. But we don't have it. So question is: why? By signatures it's the same thing, and there isn't any implementation, so delegates with same signature are one and same with many aliases...
Is it C# defect or there are reasons for it? As to me, i don't see any.
There's no implicit conversion between those two delegates for the same reason that there's no implicit conversion between these two types:
public sealed class Foo1
{
public string Value { get; set; }
}
public sealed class Foo2
{
public string Value { get; set; }
}
Just because two classes have the same fields doesn't mean that you should be able to treat one as if it were another. The same logic applies to delegates (which are also types, mind you).
There is semantic meaning applied to the creation of that type. If someone created a Foo1 they want it to be a Foo1, not a Foo2. If they're going out of their way to use a Foo1 where a Foo2 is expected, it's a big red flag that even though the types appear similar, there is a semantic difference between these two types. If the programmer knows something that the compiler doesn't, they can use an explicit conversion of some sort to indicate that they know what they're doing.
(The previous paragraph was intentionally written to apply equally to your delegates, and the classes I provided above.)

Can I use some other class's function as a delegate?

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.

Categories

Resources