C# declare delegate signature from existing function - c#

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.

Related

Referencing a delegate via another delegate in 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.

how to allow access to method to only be passed as a delegate but not executed?

I have a private method I would like to allow access to only to be passed as a delegate but not be executed otherwise.
for example:
class a
{
public delegate int myDelegate(int a);
public static int myMethod(int data, myDelegate action)
{
//my code
}
private static int methodA(int a){ //code}
private static int methodb(int a){ //code}
}
class b
{
public void anotherMethod()
{
var doAction = new myDelegate(methodA);
result = myMethod(8, doAction);
}
}
so in my example I would like methodA and MethodB to only be executed from within class a, but still enabling access to them so they can be used as delegates to be passed to methods from class a.
is it at all possible?
currently I am getting an error "methodA is inaccessible due to protection level"
What you are saying is not possible. Once a class has an instance of a delegate, no one can stop it from calling it. So if class B were able to pass a delegate to myMethod, it would also be able to call that delegate directly, unless methodA and methodB need special parameters, that only A knows about, to do anything useful.
One way of doing something similar is to create an enum called something like MethodOfA and declare MethodA and MethodB as the possible values of the enum. In class A declare a private Dictionary<MethodOfA, MyDelegate> methodDict that records what each enum value correspond to. Then declare another overload of myMethod that takes a MethodOfA like this:
public static int myMethod(int data, MethodOfA action)
=> myMethod(data, methodDict[action]);
Nevertheless, this looks like bad design to me. Maybe you don't need the overload of myMethod(int, MyDelegate) in the first place, and just check the enum to perform the corresponding action. The other thing that you might try is the strategy pattern.
If I'm understanding you correctly, you'd like to know how to use delegates (pass actions / functions) as parameters?
If so, then you should use Action<> and/or Func<> as they're delegates. Your code could look like this then:
class a
{
public int myMethod(int data, Func<int, int> func)
{
return func.Invoke(data);
}
}
class b
{
public void anotherMethod()
{
var classA = new a();
var result = classA.myMethod(8, Double);
}
private int Double(int i)
{
return i * 2;
}
}

how to pass function to different DLL included in project as reference

I have referenced one DLL (I have source code of this) say Dll_A in which there is a function
private void uploadPic(int a)
In my main project, I have a function say
private void passMe(int b)
{
}
I need to pass the above function (passMe) to uploadPic function in Dll_A, how can I do that? Is it possible?
I am able to use functions of the Dll_A from my main project, so instantiating isn't a problem, I just need a way to pass function.
===
Thanks, giving it a try. If some can edit code below
//code in main project picbackman.cs
public delegate void delObj(int v);
private void uploadSome(string path, string fName, string str)
{
delObj del1 = new delObj(updatePValue);
UploadFileResponse response = boxProvider1.UploadFiles(args1, folderString, ((Picbackman.BoxProvider.delObj)( del1)));
}
//code in different dll which is referenced in main project //Dll_A
public delegate void delObj(int v);
public UploadFileResponse UploadFiles(string[] filePathes,string folderId, delObj d)
{}
First of all your method will need to accept a delegate as one of it's parameters. That would be something like
private void uploadPic(Action<int> func,int a){
//at some point do func(someInt);
}
at another point declare anothe method or function
public class someClasse {
public vois passMe(int b){
...
}
}
First of all notice that the access modifier has changed. if they are not in the same class you will need to be able to access one from the other so they can't both be private and since they are in different assemblies internal won't work either.
when you need the delegate do like this
var obj = new someClass();
var myInt = 5; //or whatever the value is
uploadPic(obj.passMe,myInt);
notice that the method is used with out arguments. When using a method without arguments the compiler will try and convert it to a suitable delegate.
I'd recommend you not to use delegate but stick with Func/Action they are delegates but more generic
public delegate void DelObj1();
public delegate void DelObj2()
public void F(){};
var del1 = new DelObj1(F);
var del2 = new DelObj2(F);
you can't pass a del1 where a DelObj2 is needed even though you use the same method for each. You will not have that issue if you use Action/Function
Action del1 = F;
Action del2 = F;
The reason is that DelObj1 and DelObj2 are two distinct classes with the same base class Ie they are siblings in the type tree. Using Action the type is the same for both del1 and del2
You should have a look at Delegates.
From the documentation:
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
and
Delegates allow methods to be passed as parameters
So in your case you should be able to do something like this:
// define the delegate
public delegate int PictureDelegate(int value)
// define your passMe function (in the class MyClass for example)
public int passMe(int value)
{
return value + 1;
}
// when you want to use it
MyClass myInstance = new MyClass();
PictureDelegate passFunc = new PictureDelegate(myInstance.passMe);
myDll.uploadPic(passFunc, 12);

Can methods be called via an array in C#?

I have a program that will need to run different methods depending on what I want it to talk to, and I want to know if there is a way to store some sort of method pointer or something of that sort in an array. So I want an array where each element would be something like this:
[Boolean: Do_this?] [Function_pointer] [Data to pass to the function]
So basically, I can put this into a for loop and not call each function individually. Another block of code would fill in the Boolean of whether to run this function or not, and then my for loop would go through and run the function with its appropriate data if the Boolean is true.
I know delegates are similar to function pointers, but if that is the answer here, I'm not entirely sure how I would construct what I want to construct.
Is this possible in C#?
Sure is, although, to do it this way, you need all methods to have the same signature:
Lets say you had two methods:
public int Moop(string s){ return 1; }
public int Moop2(string s){ return 2; }
You could do:
var funcs = new Func<string, int>[]{ Moop, Moop2 };
And to call:
var val = funcs[0]("hello");
You could declare a specific object type to hold in a delegate, a flag that indicates whether to do that or now and the data. Note that what you are describing is very similar to events as they are also defined by a callback and some event data.
The skeletal model would look something like this, assuming all methods you want to call have the same signature (you can work around that, if you need a whole bunch of various signatures by using reflection):
// This reflects the signature of the methods you want to call
delegate void theFunction(ActionData data);
class ActionData
{
// put whatever data you would want to pass
// to the functions in this wrapper
}
class Action
{
public Action(theFunction action, ActionData data, bool doIt)
{
this.action = action;
this.data = data;
this.doIt = doIt;
}
public bool doIt
{
get;
set;
}
public ActionData data
{
get;
set;
}
public theFunction action
{
get;
set;
}
public void run()
{
if (doIt)
action(data);
}
}
And a regular use case would look something like this:
class Program
{
static void someMethod(ActionData data)
{
Console.WriteLine("SUP");
}
static void Main(string[] args)
{
Action[] actions = new Action[] {
new Action(Program.someMethod, new ActionData(), true)
};
foreach(Action a in actions)
a.run();
}
}
Yes, you can.
If all your functions share the same signature you might want to store delegates in your collection, otherwise I would go for System.Reflection.MethodInfo, which you can use later on by calling Invoke method. Parameters would be stored as array of objects - that's what Invoke expects.
If using reflection is too slow you can use Reflection.Emit to generate dynamic methods at runtime.
I would just create a List<Action>. Action is a delegate that takes no parameters and returns no results. You can use currying and lambdas such that the actual actions can call a method that has parameters. In the case where you don't actually want to run it, just don't add it to the list in the first place (or add an action that does nothing I guess).
To add an item it might look something like:
list.Add(() => someobject.someMethod(firstArgument, secondArgument));
list.Add(() => anotherObject.anotherMethod(oneArgument));
Then you can just run all of the actions when you want to:
foreach(Action action in list)
{
action();
}
This is exactly what you would use delegates for. Delegates are, more or less, type-checked function pointers. You can create some delegates and put them into an array.
Func<int, int> [] funcs = new Func<int,int>[] { x => 2 * x, x => x * x };
foreach(var fn in funcs)
{
Console.WriteLine(fn(3));
Console.WriteLine(fn(8));
}

Why can delegates can be used interchangeably for Class methods and Static functions?

I've been using delegates for many years, and haven't really given them much thought.
But I recently got egg on my face by assuming that delegates stored a this reference when referencing a class method.
The below example illustrates the gap in my understanding.
public class SomeClass
{
public SomeClass(int someProperty)
{
SomeProperty = someProperty;
}
public int SomeProperty
{
get;
set;
}
// Throw in a Member field into the mix
public int ClassAdd(int x, int y)
{
return x + y + SomeProperty;
}
}
public static class SomeStaticClass
{
public static int StaticAdd(int x, int y)
{
return x + y;
}
}
Why is it that I can add both static and instance subscribers?
class TestClass
{
delegate int myAddDelegate(int x, int y);
private void UseDelegates()
{
myAddDelegate algorithm;
algorithm = new SomeClass(3).ClassAdd;
// Surprised that I could add static methods to my delegate?
algorithm += SomeStaticClass.StaticAdd;
// I'm fine with just one of the results being returned.
int answer = algorithm(5, 10);
}
}
What is actually going on? ;)
If you create a delegate referring to an instance method, it will capture this (or the relevant reference) in the field backing the Target property of the delegate. If you create a delegate referring to a static method, the Target will be null. Logically there's no need to have an instance if you're using a static method.
As one added complications, you can capture extension methods as if they were instance methods on the extended type:
static class Extensions
{
public static void Foo(this string x)
{
Console.WriteLine("Calling Foo on " + x);
}
}
class Test
{
static void Main()
{
Action action = "text".Foo;
Console.WriteLine(action.Target); // Prints "text"
}
}
As for why you can do all of this: because it's useful, and there's no reason not to allow you to do it :)
There are no static functions in C#, they are actually static methods (so there are static and instance methods). Every delegate basically is pointer to method and this pointer on which the method will be executed, it is Target property of delegate. In case of static method it will be null. Since delegate carry reference to objects it can cause memory leaks if you forget to unsubscribe.
The beauty of delegates is that they just work, for both static and instance methods. If you assign a static method to a delegate, the static method is simply used as-is, since it doesn't need any non-static context to work. For instance methods, a reference to the instance is stored along the method pointer, so that the necessary context (the this reference) is available when the method is called. This means that when you assign an instance method to a delegate, you must also provide an instance - either by specifying it explicitly, or by assigning to the delegate from inside an instance context.
Most of the time, this 'just works', and you don't need to think about anything. There is one caveat though: If you assign an instance method to a delegate, you create another reference to the instance, and as long as the method remains assigned to the delegate (or subscribed to an event), there will also be a reference to the instance, so the GC will never collect it. This is why you should always unsubscribe from all events when cleaning up after yourself.

Categories

Resources