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

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.

Related

Difference between Action and delegate instantiation and accessibility

Why is MyDeler "static", as in I can access MyDeler through the class name, but I can't explicity say public "static" delegate void MyDeler(), nor can I access d through an instance of MyClass, as in new MyClass.d()?
Further, why is it that I have to new up a MyClass to use MyVoidAction?
See code below:
using System;
public class MyClass
{
public delegate void MyDeler();
public Action MyVoidAction;
}
class MainClass
{
static void Main()
{
MyClass.MyDeler d = () => Console.WriteLine("my deler");
d();
// MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
MyClass meClass = new MyClass();
meClass.MyVoidAction = () => Console.WriteLine("my void action");
meClass.MyVoidAction();
}
}
I looked up this answer: Accessibility between Action and Delegate
That cleared up a lot, but I'm not sure I'm 100% on this. So according to that answer, the delegate void MyDeler() defines a type, which confuses me because I imagine something like this:
using System;
class MainClass
{
class MyClass
{
public static class DelegateClass
{
public void DoDel() // isn't even legal?
{
Console.WriteLine("DoDel()");
}
}
}
static void Main()
{
//MyClass.DelegateClass d = new asdf // ??? something like this?
}
}
Help appreciated!
Let's demystify this:
When you declare MyDeler:
public delegate void MyDeler();
What you are doing is defining a type of method to which execution will be "delegated". In other words, you are saying there is method out there that follows this signature and I intend to keep references to it. In order for the compiler to identify these references, this type will be used.
It follows then that you will need to actually have a real pointer to the method, since this is just your "definition". That's why you will need a variable of type "MyDeler" to which you can assign the actual method to call:
MyClass.MyDeler d = () => Console.WriteLine("my deler");
This line is saying "create a variable named d of type MyClass.MyDeler that holds a reference to this inline method". From here on, when you call d(); the pointer will actually execute the inline method.
For the action:
public Action MyVoidAction;
You are now declaring a public property of the class. Therefore, you need an instance of the class before you can use this property.
The trick here is that Action is a known definition of a delegate. Microsoft has a built-in type that you can use instead of declaring your own void MyDeler();. It's essentially syntactical sugar but remember, it's still a type and as you have created a public property, you now need to assign it the method that will actually execute and as we discussed before, you need an instance:
MyClass meClass = new MyClass(); //Instance creation
meClass.MyVoidAction = () => Console.WriteLine("my void action"); //Tell your delegate what to delegate to.
meClass.MyVoidAction(); //Run the inline method!
I hope that helps.
MyDeler is a type declaration, not a variable declaration. You can't store things in it or assign to it.
To create a field for storing a MyDeler instance, add this line to MyClass:
public MyDeler MyDelerField;
Now you can assign to it.
Why is MyDeler "static", as in I can access MyDeler through the class name, but I can't explicity say public "static" delegate void MyDeler(), nor can I access d through an instance of MyClass, as in new MyClass.d()?
The declaration of MyDeler declares a type within MyClass. It's similar to declaring any other nested type, like:
class MyClass
{
public class MyNestedClass { }
}
It is a member of the type MyClass, not of any actual instance of MyClass, nor even of the class MyClass as a static member would be.
A nested type is neither "instance" nor "static", because it's part of the type system, not part of the class itself.
why is it that I have to new up a MyClass to use MyVoidAction?
Because MyVoidAction is a member of the class, and is an instance member. So you are required to have an instance of the class to access it.
the delegate void MyDeler() defines a type, which confuses me because I imagine something like this
Your declaration in that example of public static class DelegateClass is doing something completely different. An unfortunate aspect of C# is the use of static to refer to a variety of different things. It's not quite as bad as in Java, but it can still be confusing (as you're finding out).
In that declaration, the use of the word static does not make DelegateClass a "static member" of the containing type MyClass. Instead, the word static as part of a class declaration means that the entire class will contain only static members.
Thus, when you declare DoDel() without the static keyword, you are attempting to declare an instance member, i.e. that method, in a class where you've promised to declare only static members. If you add static to the method declaration, it would compile.
Not that doing so would make the DelegateClass class in that example similar to the MyVoidAction member in your other example. It's still a type declaration, declaring a nested type within the MyClass class, and would still follow the rules for types, not class members. But I hope that at least explains to you why the example that's confusing you works the way it does.
Action and a delegate of a method with no parameters and that returns void are formally the same thing.
If u take a look to: https://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx you can see that:
You can use this delegate to pass a method as a parameter without
explicitly declaring a custom delegate.
I hope this example helps:
public delegate void DelegateMyDeler(); //This is a custom delegate
public class MyClass
{
public DelegateMyDeler MyDeler; //This use your custom delegate
public Action MyVoidAction; // This use Action delegate
}
class MainClass
{
static void Main()
{
// MyClass.MyDeler d = () => Console.WriteLine("my deler"); // Now this is not allowed too!
// d();
// MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
MyClass meClass = new MyClass();
meClass.MyDeler = () => Console.WriteLine("my deler");
meClass.MyDeler();
meClass.MyVoidAction = () => Console.WriteLine("my void action");
meClass.MyVoidAction();
//but you can do (you custom delegate is defined out of the class in this case
//so you have not to add the class prefix):
DelegateMyDeler d = () => Console.WriteLine("my deler 2");
d();
// or
DelegateMyDeler d3 = () => Console.WriteLine("my deler 3");
d3.Invoke();
// and in a real case, for example:
DelegateMyDeler undeterminedMethod;
int x = 3;
switch (x)
{
case 1:
undeterminedMethod = deler1;
break;
case 2:
undeterminedMethod = deler2;
break;
case 3:
undeterminedMethod = deler3;
break;
default:
undeterminedMethod = null;
break;
}
undeterminedMethod?.Invoke(); //In case x is minor than 1 or major than 3, nothing happens
}
static void deler1() { Console.WriteLine("my deler 1"); }
static void deler2() { Console.WriteLine("my deler 2"); }
static void deler3() { Console.WriteLine("my deler 3"); }
}

Static modifier requirement in class/page

EDIT : Sorry. It seems I got a little confused. I was attempting to call a non-static method within a static method, and it wasn't working. They were in the same class. That led me to (incorrectly) assume that I cannot call a non-static without instantiation, even though they belong to the same class.
Since I already created the question, allow me to change the question a little. Why can I not call a non-static method within a static one? Here's my code so that you can tell me if I'm just screwing myself over with something silly:
public class DataAccessObjectClass
{
public static IList<Records> GetAllRecords(Dictionary<string,string> searchDic)
{
string query = BuildSearchQuery(searchDic); //error: object ref. required
}
public string BuildSearchQuery(Dictionary<string,string> searchDic)
{
string query = "";
//build the query
return string;
}
}
Is it something in the System.Web.UI.Page class?
No, It is because you're already inside the instance method. There is an implicit instance this which already exist in the context, this instance will be used to call that method.
There is nothing special with Page class, in any class you can do the same, You can call whatever instance method from another instance method without an instance(although you're technically using this as implicit reference).
You don't need to instantiate the class because it's already been instantiated for you.
Consider the class
public class C
{
public void f() { g(); }
public void g() { }
}
Now, you cannot simply call C.g();, you need an instance to call it on. new C().g(); would work, but so would
var c = new C();
c.g();
The call from f to g already has an instance to call g on, which is this. There, g(); simply means this.g();. c.f(); would end up calling c.g() from within f.
For your edited question, consider this class:
public class D
{
public static void f() { g(); } // error
public void g() { }
}
Now, because D.f is static, you could call it as simply D.f();. In that case, there isn't any instance of D at all yet, so you have no instance to call g on. (Or, if you do create instances of D first, the system wouldn't know which of those instances to call g on.)
Actually, Page_Load is beeing called when the page is rendered, so, there is an instantiate of the class DefaultPage, and this object is the one that is calling to Page_Load and to GetObjects.

c# cannot declare static and non static methods with same parameters?

If I try to declare static and non-static methods with the same parameters compiler returns an error: type 'Test' already defines a member called 'Load' with the same parameter types.
class Test
{
int i = 0;
public int I
{
get { return i; }
set { i = value; }
}
public bool Load(int newValue)
{
i = newValue;
return true;
}
public static Test Load(int newValue)
{
Test t = new Test();
t.I = newValue;
return t;
}
As far as I know these two methods can not be mixed, non static method is called on object whereas static method is called on class, so why does compiler not allow something like this and is there a way to do something similar?
If your Test class had a method like this:
public void CallLoad()
{
Load(5);
}
the compiler would not know which Load() to use. Calling a static method without the class name is entirely allowed for class members.
As for how to do something similar, I guess your best bet is to give the methods similar but different names, such as renaming the static method to LoadTest() or LoadItem().
Inside the class itself, you call both instance methods and static methods without an instance or the class name, thus making the two undistinguishable if the names and parameters are the same:
class Test
{
public void Foo()
{
Load(0); // Are you trying to call the static or the instance method?
}
// ...
}
The signature of a method is the combination of name and parameters (number and types).
In your case, your 2 methods have the same identical signature. The fact that one is static and other one is not makes no difference in accepting them as valid methods for the class.
I don't think so. if a non static method in this class calls Load(intValue). which method will be called?
Both methods have the same name, defined in the same class (scope) and with the same signature. C# does not allow this.
The problem is not related with writing this or the classname. C# specs allow you to call static methods using object instances:
AClass objectA = new AClass();
objectA.CallStaticMethod();
This code is valid so the compiler never has a way to know if you're calling a static or an instance method.
In C# a method cannot be overloaded by return type. It must at least have a different set of parameters, regardless if the method is static or not.

Referencing a function in a variable?

Say I have a function. I wish to add a reference to this function in a variable.
So I could call the function 'foo(bool foobar)' from a variable 'bar', as if it was a function. EG. 'bar(foobar)'.
How?
It sounds like you want to save a Func to a variable for later use. Take a look at the examples here:
using System;
public class GenericFunc
{
public static void Main()
{
// Instantiate delegate to reference UppercaseString method
Func<string, string> convertMethod = UppercaseString;
string name = "Dakota";
// Use delegate instance to call UppercaseString method
Console.WriteLine(convertMethod(name));
}
private static string UppercaseString(string inputString)
{
return inputString.ToUpper();
}
}
See how the method UppercaseString is saved to a variable called convertMethod which can then later be called: convertMethod(name).
Using delegates
void Foo(bool foobar)
{
/* method implementation */
}
using Action delegate
Public Action<bool> Bar;
Bar = Foo;
Call the function;
bool foobar = true;
Bar(foobar);
Are you looking for Delegates?
You need to know the signature of the function, and create a delegate.
There are ready-made delegates for functions that return a value and for functions that have a void return type. Both of the previous links point to generic types that can take up to 15 or so type arguments (thus can serve for functions taking up to that many arguments).
If you intend to use references to functions in a scope larger than a local scope, you can consider defining your own custom delegates. But most of the time, Action and Func do very nicely.
Update:
Take a look at this question regarding the choice between defining your own delegates or not.

c# delegate and abstract class

I currently have 2 concrete methods in 2 abstract classes. One class contains the current method, while the other contains the legacy method. E.g.
// Class #1
public abstract class ClassCurrent<T> : BaseClass<T> where T : BaseNode, new()
{
public List<T> GetAllRootNodes(int i)
{
//some code
}
}
// Class #2
public abstract class MyClassLegacy<T> : BaseClass<T> where T : BaseNode, new()
{
public List<T> GetAllLeafNodes(int j)
{
//some code
}
}
I want the corresponding method to run in their relative scenarios in the app. I'm planning to write a delegate to handle this. The idea is that I can just call the delegate and write logic in it to handle which method to call depending on which class/project it is called from (at least thats what I think delegates are for and how they are used).
However, I have some questions on that topic (after some googling):
1) Is it possible to have a delegate that knows the 2 (or more) methods that reside in different classes?
2) Is it possible to make a delegate that spawns off abstract classes (like from the above code)? (My guess is a no, since delegates create concrete implementation of the passed-in classes)
3) I tried to write a delegate for the above code. But I'm being technically challenged:
public delegate List<BaseNode> GetAllNodesDelegate(int k);
GetAllNodesDelegate del = new GetAllNodesDelegate(ClassCurrent<BaseNode>.GetAllRootNodes);
I got the following error:
An object reference is required for the non-static field, method, property ClassCurrent<BaseNode>.GetAllRootNodes(int)
I might have misunderstood something... but if I have to manually declare a delegate at the calling class, AND to pass in the function manually as above, then I'm starting to question whether delegate is a good way to handle my problem.
Thanks.
The way you're attempting to use delegates (constructing them with new, declaring a named delegate type) suggests that you're using C# 1. If you're actually using C# 3, it's much easier than that.
Firstly, your delegate type:
public delegate List<BaseNode> GetAllNodesDelegate(int k);
Already exists. It's just:
Func<int, List<BaseNode>>
So you don't need to declare your own version of it.
Secondly, you should think of a delegate as being like an interface with only one method in it, and you can "implement" it on the fly, without having to write a named class. Just write a lambda, or assign a method name directly.
Func<int, List<BaseNode>> getNodesFromInt;
// just assign a compatible method directly
getNodesFromInt = DoSomethingWithArgAndReturnList;
// or bind extra arguments to an incompatible method:
getNodesFromInt = arg => MakeList(arg, "anotherArgument");
// or write the whole thing specially:
getNodesFromInt = arg =>
{
var result = new List<BaseNode>();
result.Add(new BaseNode());
return result;
};
A lambda is of the form (arguments) => { body; }. The arguments are comma-separated. If there's only one, you can omit the parentheses. If it takes no parameters, put a pair of empty parentheses: (). If the body is only one statement long, you can omit the braces. If it's just a single expression, you can omit the braces and the return keyword. In the body, you can refer to practically any variables and methods from the enclosing scope (apart from ref/out parameters to the enclosing method).
There's almost never any need to use new to create a delegate instance. And rarely a need to declare custom delegate types. Use Func for delegates that return a value and Action for delegates that return void.
Whenever the thing you need to pass around is like an object with one method (whether an interface or a class), then use a delegate instead, and you'll be able to avoid a lot of mess.
In particular, avoid defining interfaces with one method. It will just mean that instead of being able to write a lambda to implement that method, you'll have to declare a separate named class for each different implementation, with the pattern:
class Impl : IOneMethod
{
// a bunch of fields
public Impl(a bunch of parameters)
{
// assign all the parameters to their fields
}
public void TheOneMethod()
{
// make use of the fields
}
}
A lambda effectively does all that for you, eliminating such mechanical patterns from your code. You just say:
() => /* same code as in TheOneMethod */
It also has the advantage that you can update variables in the enclosing scope, because you can refer directly to them (instead of working with values copied into fields of a class). Sometimes this can be a disadvantage, if you don't want to modify the values.
You can have a delegate that is initialized with references to different methods depending on some conditions.
Regarding your questions:
1) I'm not sure what you mean under "knows". You can pass any method to the delegate, so if you can write method that "knows" about some other methods than you can do a similar delegate.
2) Again, delegates can be created from any method that can be executed. For example if you have an initialized local variable of type ClassCurrent<T> you can created delegate for any instance method of type ClassCurrent<T>.
3) Delegate can call only the method that actually can be called. I mean that you cannot call ClassCurrent.GetAllRootNodes because GetAllRootNodes is not a static method, so you need an instance of the ClassCurrent to call it.
The delegate can stay in any class that has access to the ClassCurrent and MyClassLegacy.
For example you can create smth like:
class SomeActionAccessor<T>
{
// Declare delegate and fied of delegate type.
public delegate T GetAllNodesDelegate(int i);
private GetAllNodesDelegate getAllNodesDlg;
// Initilaize delegate field somehow, e.g. in constructor.
public SomeActionAccessor(GetAllNodesDelegate getAllNodesDlg)
{
this.getAllNodesDlg = getAllNodesDlg;
}
// Implement the method that calls the delegate.
public T GetAllNodes(int i)
{
return this.getAllNodesDlg(i);
}
}
The delegates can wrap both static and instance method. The only difference is that for creation delegate with instance method you need instance of the class who owns the method.
Let both ClassCurrent and MyClassLegacy implement an interface INodeFetcher:
public interface INodeFetcher<T> {
List<T> GetNodes(int k);
}
For ClassCurrent call the GetAllRootNodes method from the interface's implementation and for MyLegacyClass the GetAllLeaveNodes method.
Why would you want a delegate for this? It sounds overly complex. I would just create a method in a new class that you could instansiate when you needed to call you method. This class could be given some context information to help it decide. Then I would implement logic in the new method that would decide whether to call the current method or the legacy method.
Something like this:
public class CurrentOrLegacySelector<T>
{
public CurrentOrLegacySelector(some type that describe context)
{
// .. do something with the context.
// The context could be a boolean or something more fancy.
}
public List<T> GetNodes(int argument)
{
// Return the result of either current or
// legacy method based on context information
}
}
This would give you a clean wrapper for the methods that is easy to read and understand.
As a variation of the theme suggested by Rune Grimstad I think you could use the strategy pattern (e.g.
Introduction to the GOF Strategy Pattern in C# ).
This would be especially interesting in the case where you cannot change the LegacyClass (and therefore maybe cannot easily use the "interface approach" suggested by Cornelius) and if you are using dependency injection (DI; Dependency injection). DI would (maybe) let you inject the correct implementation (concrete strategy) in the right place.
Strategy:
public interface INodeFetcher<T> {
List<T> GetNodes(int k);
}
Concrete Strategies:
public class CurrentSelector<T> : INodeFetcher<T>
{
public List<T> GetNodes(int argument)
{
// Return the result "current" method
}
}
public class LegacySelector<T> : INodeFetcher<T>
{
public List<T> GetNodes(int argument)
{
// Return the result "legacy" method
}
}
-> Inject/instantiate the correct concrete strategy.
Regards

Categories

Resources